diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java index 6bf71e41d..fd2d51e93 100644 --- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java +++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java @@ -54,13 +54,13 @@ import org.eclipse.aether.spi.connector.transport.Transporter; import org.eclipse.aether.spi.connector.transport.TransporterProvider; import org.eclipse.aether.spi.io.ChecksumProcessor; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.transfer.ChecksumFailureException; import org.eclipse.aether.transfer.NoRepositoryConnectorException; import org.eclipse.aether.transfer.NoRepositoryLayoutException; import org.eclipse.aether.transfer.TransferEvent; import org.eclipse.aether.transfer.TransferResource; import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.FileUtils; import org.eclipse.aether.util.concurrency.RunnableErrorForwarder; import org.eclipse.aether.util.concurrency.SmartExecutor; import org.eclipse.aether.util.concurrency.SmartExecutorUtils; @@ -87,6 +87,8 @@ final class BasicRepositoryConnector implements RepositoryConnector { private final Map providedChecksumsSources; + private final PathProcessor pathProcessor; + private final ChecksumProcessor checksumProcessor; private final RemoteRepository repository; @@ -113,12 +115,14 @@ final class BasicRepositoryConnector implements RepositoryConnector { private final AtomicBoolean closed; + @SuppressWarnings("checkstyle:parameternumber") BasicRepositoryConnector( RepositorySystemSession session, RemoteRepository repository, TransporterProvider transporterProvider, RepositoryLayoutProvider layoutProvider, ChecksumPolicyProvider checksumPolicyProvider, + PathProcessor pathProcessor, ChecksumProcessor checksumProcessor, Map providedChecksumsSources) throws NoRepositoryConnectorException { @@ -140,6 +144,7 @@ final class BasicRepositoryConnector implements RepositoryConnector { this.session = session; this.repository = repository; this.checksumProcessor = checksumProcessor; + this.pathProcessor = pathProcessor; this.providedChecksumsSources = providedChecksumsSources; this.executors = new ConcurrentHashMap<>(); this.closed = new AtomicBoolean(false); @@ -496,6 +501,7 @@ class GetTaskRunner extends TaskRunner implements ChecksumValidator.ChecksumFetc checksumValidator = new ChecksumValidator( file, checksumAlgorithmFactories, + pathProcessor, checksumProcessor, this, checksumPolicy, @@ -518,7 +524,7 @@ public boolean fetchChecksum(URI remote, Path local) throws Exception { @Override protected void runTask() throws Exception { - try (FileUtils.CollocatedTempFile tempFile = FileUtils.newTempFile(file)) { + try (PathProcessor.CollocatedTempFile tempFile = pathProcessor.newTempFile(file)) { final Path tmp = tempFile.getPath(); listener.setChecksumCalculator(checksumValidator.newChecksumCalculator(tmp)); for (int firstTrial = 0, lastTrial = 1, trial = firstTrial; ; trial++) { diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java index b16610e87..9cd0f1ab7 100644 --- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java +++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java @@ -32,6 +32,7 @@ import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider; import org.eclipse.aether.spi.connector.transport.TransporterProvider; import org.eclipse.aether.spi.io.ChecksumProcessor; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.transfer.NoRepositoryConnectorException; import static java.util.Objects.requireNonNull; @@ -50,6 +51,8 @@ public final class BasicRepositoryConnectorFactory implements RepositoryConnecto private final ChecksumPolicyProvider checksumPolicyProvider; + private final PathProcessor pathProcessor; + private final ChecksumProcessor checksumProcessor; private final Map providedChecksumsSources; @@ -61,11 +64,13 @@ public BasicRepositoryConnectorFactory( TransporterProvider transporterProvider, RepositoryLayoutProvider layoutProvider, ChecksumPolicyProvider checksumPolicyProvider, + PathProcessor pathProcessor, ChecksumProcessor checksumProcessor, Map providedChecksumsSources) { this.transporterProvider = requireNonNull(transporterProvider, "transporter provider cannot be null"); this.layoutProvider = requireNonNull(layoutProvider, "repository layout provider cannot be null"); this.checksumPolicyProvider = requireNonNull(checksumPolicyProvider, "checksum policy provider cannot be null"); + this.pathProcessor = requireNonNull(pathProcessor, "path processor cannot be null"); this.checksumProcessor = requireNonNull(checksumProcessor, "checksum processor cannot be null"); this.providedChecksumsSources = requireNonNull(providedChecksumsSources, "provided checksum sources cannot be null"); @@ -99,6 +104,7 @@ public RepositoryConnector newInstance(RepositorySystemSession session, RemoteRe transporterProvider, layoutProvider, checksumPolicyProvider, + pathProcessor, checksumProcessor, providedChecksumsSources); } diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java index 24fdbc3a1..850474f0a 100644 --- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java +++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java @@ -31,8 +31,8 @@ import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind; import org.eclipse.aether.spi.connector.layout.RepositoryLayout.ChecksumLocation; import org.eclipse.aether.spi.io.ChecksumProcessor; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.transfer.ChecksumFailureException; -import org.eclipse.aether.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +56,8 @@ interface ChecksumFetcher { private final Collection checksumAlgorithmFactories; + private final PathProcessor pathProcessor; + private final ChecksumProcessor checksumProcessor; private final ChecksumFetcher checksumFetcher; @@ -68,9 +70,11 @@ interface ChecksumFetcher { private final Map checksumExpectedValues; + @SuppressWarnings("checkstyle:parameternumber") ChecksumValidator( Path dataPath, Collection checksumAlgorithmFactories, + PathProcessor pathProcessor, ChecksumProcessor checksumProcessor, ChecksumFetcher checksumFetcher, ChecksumPolicy checksumPolicy, @@ -78,6 +82,7 @@ interface ChecksumFetcher { Collection checksumLocations) { this.dataPath = dataPath; this.checksumAlgorithmFactories = checksumAlgorithmFactories; + this.pathProcessor = pathProcessor; this.checksumProcessor = checksumProcessor; this.checksumFetcher = checksumFetcher; this.checksumPolicy = checksumPolicy; @@ -156,7 +161,7 @@ private boolean validateExternalChecksums(Map actualChecksums) throws continue; } Path checksumFile = getChecksumPath(checksumLocation.getChecksumAlgorithmFactory()); - try (FileUtils.TempFile tempFile = FileUtils.newTempFile()) { + try (PathProcessor.TempFile tempFile = pathProcessor.newTempFile()) { Path tmp = tempFile.getPath(); try { if (!checksumFetcher.fetchChecksum(checksumLocation.getLocation(), tmp)) { diff --git a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java index 01c3f9ae5..ce6748c79 100644 --- a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java +++ b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java @@ -36,6 +36,7 @@ import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy; import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind; import org.eclipse.aether.spi.connector.layout.RepositoryLayout; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.eclipse.aether.transfer.ChecksumFailureException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -189,6 +190,7 @@ private ChecksumValidator newValidator(Map providedChecksums, St return new ChecksumValidator( dataFile.toPath(), checksumAlgorithmFactories, + new PathProcessorSupport(), new TestChecksumProcessor(), fetcher, policy, diff --git a/maven-resolver-generator-sigstore/src/main/java/org/eclipse/aether/generator/sigstore/SigstoreSignatureArtifactGenerator.java b/maven-resolver-generator-sigstore/src/main/java/org/eclipse/aether/generator/sigstore/SigstoreSignatureArtifactGenerator.java index 7e7ca6712..e5c8ae295 100644 --- a/maven-resolver-generator-sigstore/src/main/java/org/eclipse/aether/generator/sigstore/SigstoreSignatureArtifactGenerator.java +++ b/maven-resolver-generator-sigstore/src/main/java/org/eclipse/aether/generator/sigstore/SigstoreSignatureArtifactGenerator.java @@ -37,7 +37,7 @@ import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.generator.sigstore.internal.FulcioOidHelper; import org.eclipse.aether.spi.artifact.generator.ArtifactGenerator; -import org.eclipse.aether.util.FileUtils; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.util.artifact.SubArtifact; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,13 +45,18 @@ final class SigstoreSignatureArtifactGenerator implements ArtifactGenerator { private static final String ARTIFACT_EXTENSION = ".sigstore.json"; private final Logger logger = LoggerFactory.getLogger(getClass()); + private final PathProcessor pathProcessor; private final ArrayList artifacts; private final Predicate signableArtifactPredicate; private final boolean publicStaging; private final ArrayList signatureTempFiles; SigstoreSignatureArtifactGenerator( - Collection artifacts, Predicate signableArtifactPredicate, boolean publicStaging) { + PathProcessor pathProcessor, + Collection artifacts, + Predicate signableArtifactPredicate, + boolean publicStaging) { + this.pathProcessor = pathProcessor; this.artifacts = new ArrayList<>(artifacts); this.signableArtifactPredicate = signableArtifactPredicate; this.publicStaging = publicStaging; @@ -107,7 +112,7 @@ public Collection generate(Collection ge + FulcioOidHelper.getIssuerV2(cert) + " IdP)"); - FileUtils.writeFile(signatureTempFile, p -> Files.writeString(p, bundle.toJson())); + pathProcessor.write(signatureTempFile, bundle.toJson()); long duration = System.currentTimeMillis() - start; logger.debug(" > Rekor entry " diff --git a/maven-resolver-generator-sigstore/src/main/java/org/eclipse/aether/generator/sigstore/SigstoreSignatureArtifactGeneratorFactory.java b/maven-resolver-generator-sigstore/src/main/java/org/eclipse/aether/generator/sigstore/SigstoreSignatureArtifactGeneratorFactory.java index c512eeb48..bb51ec20c 100644 --- a/maven-resolver-generator-sigstore/src/main/java/org/eclipse/aether/generator/sigstore/SigstoreSignatureArtifactGeneratorFactory.java +++ b/maven-resolver-generator-sigstore/src/main/java/org/eclipse/aether/generator/sigstore/SigstoreSignatureArtifactGeneratorFactory.java @@ -31,6 +31,7 @@ import org.eclipse.aether.spi.artifact.ArtifactPredicateFactory; import org.eclipse.aether.spi.artifact.generator.ArtifactGenerator; import org.eclipse.aether.spi.artifact.generator.ArtifactGeneratorFactory; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.util.ConfigUtils; @Singleton @@ -40,10 +41,13 @@ public final class SigstoreSignatureArtifactGeneratorFactory implements Artifact public static final String NAME = "sigstore"; private final ArtifactPredicateFactory artifactPredicateFactory; + private final PathProcessor pathProcessor; @Inject - public SigstoreSignatureArtifactGeneratorFactory(ArtifactPredicateFactory artifactPredicateFactory) { + public SigstoreSignatureArtifactGeneratorFactory( + ArtifactPredicateFactory artifactPredicateFactory, PathProcessor pathProcessor) { this.artifactPredicateFactory = artifactPredicateFactory; + this.pathProcessor = pathProcessor; } @Override @@ -68,7 +72,7 @@ private ArtifactGenerator newInstance(RepositorySystemSession session, Collectio SigstoreConfigurationKeys.CONFIG_PROP_PUBLIC_STAGING); return new SigstoreSignatureArtifactGenerator( - artifacts, artifactPredicateFactory.newInstance(session)::hasChecksums, publicStaging); + pathProcessor, artifacts, artifactPredicateFactory.newInstance(session)::hasChecksums, publicStaging); } @Override diff --git a/maven-resolver-generator-sigstore/src/test/java/org/eclipse/aether/generator/sigstore/SigstoreSignerFactoryTest.java b/maven-resolver-generator-sigstore/src/test/java/org/eclipse/aether/generator/sigstore/SigstoreSignerFactoryTest.java index b8f6badac..30423db6d 100644 --- a/maven-resolver-generator-sigstore/src/test/java/org/eclipse/aether/generator/sigstore/SigstoreSignerFactoryTest.java +++ b/maven-resolver-generator-sigstore/src/test/java/org/eclipse/aether/generator/sigstore/SigstoreSignerFactoryTest.java @@ -34,6 +34,7 @@ import org.eclipse.aether.spi.artifact.ArtifactPredicate; import org.eclipse.aether.spi.artifact.ArtifactPredicateFactory; import org.eclipse.aether.spi.artifact.generator.ArtifactGenerator; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -57,7 +58,7 @@ private SigstoreSignatureArtifactGeneratorFactory createFactory() throws Excepti when(artifactPredicateFactory.newInstance(any(RepositorySystemSession.class))) .thenReturn(artifactPredicate); - return new SigstoreSignatureArtifactGeneratorFactory(artifactPredicateFactory); + return new SigstoreSignatureArtifactGeneratorFactory(artifactPredicateFactory, new PathProcessorSupport()); } private RepositorySystemSession createSession() { diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultPathProcessor.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultPathProcessor.java index f27d85382..87e22befb 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultPathProcessor.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultPathProcessor.java @@ -21,95 +21,11 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.nio.file.AccessDeniedException; -import java.nio.file.FileSystemException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.FileTime; - -import org.eclipse.aether.spi.io.PathProcessor; -import org.eclipse.aether.util.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.eclipse.aether.spi.io.PathProcessorSupport; /** - * A utility class helping with file-based operations. + * Exposing path processor (from SPI). */ @Singleton @Named -public class DefaultPathProcessor implements PathProcessor { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Override - public void setLastModified(Path path, long value) throws IOException { - try { - Files.setLastModifiedTime(path, FileTime.fromMillis(value)); - } catch (FileSystemException e) { - // MRESOLVER-536: Java uses generic FileSystemException for some weird cases, - // but some subclasses like AccessDeniedEx should be re-thrown - if (e instanceof AccessDeniedException) { - throw e; - } - logger.trace("Failed to set last modified date: {}", path, e); - } - } - - @Override - public void write(Path target, String data) throws IOException { - FileUtils.writeFile(target, p -> Files.write(p, data.getBytes(StandardCharsets.UTF_8))); - } - - @Override - public void write(Path target, InputStream source) throws IOException { - FileUtils.writeFile(target, p -> Files.copy(source, p, StandardCopyOption.REPLACE_EXISTING)); - } - - @Override - public long copy(Path source, Path target, ProgressListener listener) throws IOException { - try (InputStream in = new BufferedInputStream(Files.newInputStream(source)); - FileUtils.CollocatedTempFile tempTarget = FileUtils.newTempFile(target); - OutputStream out = new BufferedOutputStream(Files.newOutputStream(tempTarget.getPath()))) { - long result = copy(out, in, listener); - tempTarget.move(); - return result; - } - } - - private long copy(OutputStream os, InputStream is, ProgressListener listener) throws IOException { - long total = 0L; - byte[] buffer = new byte[1024 * 32]; - while (true) { - int bytes = is.read(buffer); - if (bytes < 0) { - break; - } - - os.write(buffer, 0, bytes); - - total += bytes; - - if (listener != null && bytes > 0) { - try { - listener.progressed(ByteBuffer.wrap(buffer, 0, bytes)); - } catch (Exception e) { - // too bad - } - } - } - - return total; - } - - @Override - public void move(Path source, Path target) throws IOException { - Files.move(source, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); - } -} +public class DefaultPathProcessor extends PathProcessorSupport {} diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource.java index ec629e7ae..85c9be19f 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource.java @@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; +import java.util.stream.Collectors; import org.eclipse.aether.MultiRuntimeException; import org.eclipse.aether.RepositorySystemSession; @@ -44,14 +45,13 @@ import org.eclipse.aether.internal.impl.LocalPathComposer; import org.eclipse.aether.repository.ArtifactRepository; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.FileUtils; import org.eclipse.aether.util.repository.RepositoryIdHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.util.Objects.requireNonNull; -import static java.util.stream.Collectors.toList; /** * Compact file {@link FileTrustedChecksumsSourceSupport} implementation that use specified directory as base @@ -132,6 +132,8 @@ public final class SummaryFileTrustedChecksumsSource extends FileTrustedChecksum private final RepositorySystemLifecycle repositorySystemLifecycle; + private final PathProcessor pathProcessor; + private final ConcurrentHashMap> checksums; private final ConcurrentHashMap changedChecksums; @@ -140,9 +142,12 @@ public final class SummaryFileTrustedChecksumsSource extends FileTrustedChecksum @Inject public SummaryFileTrustedChecksumsSource( - LocalPathComposer localPathComposer, RepositorySystemLifecycle repositorySystemLifecycle) { + LocalPathComposer localPathComposer, + RepositorySystemLifecycle repositorySystemLifecycle, + PathProcessor pathProcessor) { this.localPathComposer = requireNonNull(localPathComposer); this.repositorySystemLifecycle = requireNonNull(repositorySystemLifecycle); + this.pathProcessor = requireNonNull(pathProcessor); this.checksums = new ConcurrentHashMap<>(); this.changedChecksums = new ConcurrentHashMap<>(); this.onShutdownHandlerRegistered = new AtomicBoolean(false); @@ -325,14 +330,12 @@ private void saveRecordedLines() { result.putAll(recordedLines); LOGGER.info("Saving {} checksums to '{}'", result.size(), summaryFile); - FileUtils.writeFileWithBackup( + pathProcessor.writeWithBackup( summaryFile, - p -> Files.write( - p, - result.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .map(e -> e.getValue() + " " + e.getKey()) - .collect(toList()))); + result.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .map(e -> e.getValue() + " " + e.getKey()) + .collect(Collectors.joining(System.lineSeparator()))); } catch (IOException e) { exceptions.add(e); } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource.java index 255e6f0a9..92585d35f 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource.java @@ -34,6 +34,7 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.aether.MultiRuntimeException; @@ -45,9 +46,9 @@ import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactResult; import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.spi.resolution.ArtifactResolverPostProcessor; import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.FileUtils; import org.eclipse.aether.util.repository.RepositoryIdHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -136,6 +137,8 @@ public final class GroupIdRemoteRepositoryFilterSource extends RemoteRepositoryF private final RepositorySystemLifecycle repositorySystemLifecycle; + private final PathProcessor pathProcessor; + private final ConcurrentHashMap rules; private final ConcurrentHashMap ruleFiles; @@ -145,8 +148,10 @@ public final class GroupIdRemoteRepositoryFilterSource extends RemoteRepositoryF private final AtomicBoolean onShutdownHandlerRegistered; @Inject - public GroupIdRemoteRepositoryFilterSource(RepositorySystemLifecycle repositorySystemLifecycle) { + public GroupIdRemoteRepositoryFilterSource( + RepositorySystemLifecycle repositorySystemLifecycle, PathProcessor pathProcessor) { this.repositorySystemLifecycle = requireNonNull(repositorySystemLifecycle); + this.pathProcessor = requireNonNull(pathProcessor); this.rules = new ConcurrentHashMap<>(); this.ruleFiles = new ConcurrentHashMap<>(); this.recordedRules = new ConcurrentHashMap<>(); @@ -299,7 +304,8 @@ private void saveRecordedLines() { result.add("# Recorded entries"); result.addAll(recorded); logger.info("Saving {} groupIds to '{}'", result.size(), entry.getValue()); - FileUtils.writeFileWithBackup(entry.getValue(), p -> Files.write(p, result)); + pathProcessor.writeWithBackup( + entry.getValue(), result.stream().collect(Collectors.joining(System.lineSeparator()))); } catch (IOException e) { exceptions.add(e); } diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java index 40f9ea3b4..fc2c9cd68 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java @@ -38,7 +38,9 @@ import org.eclipse.aether.impl.VersionResolver; import org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager; import org.eclipse.aether.internal.impl.filter.Filters; -import org.eclipse.aether.internal.test.util.*; +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.internal.test.util.TestLocalRepositoryManager; +import org.eclipse.aether.internal.test.util.TestUtils; import org.eclipse.aether.metadata.Metadata; import org.eclipse.aether.repository.LocalArtifactRegistration; import org.eclipse.aether.repository.LocalArtifactRequest; @@ -61,6 +63,7 @@ import org.eclipse.aether.spi.connector.ArtifactDownload; import org.eclipse.aether.spi.connector.MetadataDownload; import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilterSource; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.eclipse.aether.transfer.ArtifactNotFoundException; import org.eclipse.aether.transfer.ArtifactTransferException; import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy; @@ -110,7 +113,7 @@ void setup() { private DefaultArtifactResolver setupArtifactResolver( VersionResolver versionResolver, UpdateCheckManager updateCheckManager) { return new DefaultArtifactResolver( - new TestPathProcessor(), + new PathProcessorSupport(), new StubRepositoryEventDispatcher(), versionResolver, updateCheckManager, diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java index 988d62942..095e554d8 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultDeployerTest.java @@ -36,7 +36,6 @@ import org.eclipse.aether.deployment.DeployRequest; import org.eclipse.aether.deployment.DeploymentException; import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.internal.test.util.TestPathProcessor; import org.eclipse.aether.internal.test.util.TestUtils; import org.eclipse.aether.metadata.DefaultMetadata; import org.eclipse.aether.metadata.MergeableMetadata; @@ -48,6 +47,7 @@ import org.eclipse.aether.spi.connector.MetadataDownload; import org.eclipse.aether.spi.connector.MetadataUpload; import org.eclipse.aether.spi.connector.RepositoryConnector; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.eclipse.aether.transfer.MetadataNotFoundException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -85,7 +85,7 @@ void setup() throws IOException { connectorProvider = new StubRepositoryConnectorProvider(); deployer = new DefaultDeployer( - new TestPathProcessor(), + new PathProcessorSupport(), new StubRepositoryEventDispatcher(), connectorProvider, new StubRemoteRepositoryManager(), diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java index 59fb22ac3..e6fa5e84f 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultInstallerTest.java @@ -32,10 +32,13 @@ import org.eclipse.aether.installation.InstallRequest; import org.eclipse.aether.installation.InstallResult; import org.eclipse.aether.installation.InstallationException; -import org.eclipse.aether.internal.test.util.*; +import org.eclipse.aether.internal.test.util.TestFileUtils; +import org.eclipse.aether.internal.test.util.TestLocalRepositoryManager; +import org.eclipse.aether.internal.test.util.TestUtils; import org.eclipse.aether.metadata.DefaultMetadata; import org.eclipse.aether.metadata.Metadata; import org.eclipse.aether.metadata.Metadata.Nature; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -84,7 +87,7 @@ void setup() throws IOException { localArtifactFile = new File(session.getLocalRepository().getBasedir(), localArtifactPath); installer = new DefaultInstaller( - new TestPathProcessor(), + new PathProcessorSupport(), new StubRepositoryEventDispatcher(), Collections.emptyMap(), Collections.emptyMap(), diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSourceTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSourceTest.java index ecc09c821..2646d783c 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSourceTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSourceTest.java @@ -31,6 +31,7 @@ import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.NoLocalRepositoryManagerException; import org.eclipse.aether.spi.checksums.TrustedChecksumsSource; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -42,7 +43,8 @@ public class SummaryFileTrustedChecksumsSourceTest extends FileTrustedChecksumsSourceTestSupport { @Override protected FileTrustedChecksumsSourceSupport prepareSubject(RepositorySystemLifecycle lifecycle) { - return new SummaryFileTrustedChecksumsSource(new DefaultLocalPathComposer(), lifecycle); + return new SummaryFileTrustedChecksumsSource( + new DefaultLocalPathComposer(), lifecycle, new PathProcessorSupport()); } @Override diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSourceTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSourceTest.java index 5f6e0c3fb..4a60622ad 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSourceTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSourceTest.java @@ -30,6 +30,7 @@ import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.spi.io.PathProcessorSupport; /** * UT for {@link GroupIdRemoteRepositoryFilterSource}. @@ -40,8 +41,8 @@ public class GroupIdRemoteRepositoryFilterSourceTest extends RemoteRepositoryFil @Override protected GroupIdRemoteRepositoryFilterSource getRemoteRepositoryFilterSource( DefaultRepositorySystemSession session, RemoteRepository remoteRepository) { - return groupIdRemoteRepositoryFilterSource = - new GroupIdRemoteRepositoryFilterSource(new DefaultRepositorySystemLifecycle()); + return groupIdRemoteRepositoryFilterSource = new GroupIdRemoteRepositoryFilterSource( + new DefaultRepositorySystemLifecycle(), new PathProcessorSupport()); } @Override diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/PathProcessor.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/PathProcessor.java index e896eba66..cc41f737f 100644 --- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/PathProcessor.java +++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/PathProcessor.java @@ -18,6 +18,7 @@ */ package org.eclipse.aether.spi.io; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; @@ -56,7 +57,7 @@ default long lastModified(Path path, long defValue) { * and can be multiple, ranging from "file not found" to cases when FS does not support the setting the mtime. * @since 2.0.0 */ - void setLastModified(Path path, long value) throws IOException; + boolean setLastModified(Path path, long value) throws IOException; /** * Returns size of file, if exists. @@ -94,6 +95,28 @@ default long size(Path path, long defValue) { */ void write(Path target, InputStream source) throws IOException; + /** + * Writes the given data to a file. UTF-8 is assumed as encoding for the data. Creates the necessary directories for + * the target file. In case of an error, the created directories will be left on the file system. + * + * @param target The file to write to, must not be {@code null}. This file will be overwritten. + * @param data The data to write, may be {@code null}. + * @throws IOException If an I/O error occurs. + * @since 2.0.13 + */ + void writeWithBackup(Path target, String data) throws IOException; + + /** + * Writes the given stream to a file. Creates the necessary directories for the target file. In case of an error, + * the created directories will be left on the file system. + * + * @param target The file to write to, must not be {@code null}. This file will be overwritten. + * @param source The stream to write to the file, must not be {@code null}. + * @throws IOException If an I/O error occurs. + * @since 2.0.13 + */ + void writeWithBackup(Path target, InputStream source) throws IOException; + /** * Moves the specified source file to the given target file. If the target file already exists, it is overwritten. * Creates the necessary directories for the target file. In case of an error, the created directories will be left @@ -149,7 +172,68 @@ default void copyWithTimestamp(Path source, Path target) throws IOException { * @see PathProcessor#copy(Path, Path, ProgressListener) */ interface ProgressListener { - void progressed(ByteBuffer buffer) throws IOException; } + + // Temporary files + + /** + * A temporary file, that is removed when closed. + * + * @since 2.0.13 + */ + interface TempFile extends Closeable { + /** + * Returns the path of the created temp file. + */ + Path getPath(); + } + + /** + * A collocated temporary file, that resides next to a "target" file, and is removed when closed. + * + * @since 2.0.13 + */ + interface CollocatedTempFile extends TempFile { + /** + * Upon close, atomically moves temp file to target file it is collocated with overwriting target (if exists). + * Invocation of this method merely signals that caller ultimately wants temp file to replace the target + * file, but when this method returns, the move operation did not yet happen, it will happen when this + * instance is closed. + *

+ * Invoking this method without writing to temp file {@link #getPath()} (thus, not creating a temp + * file to be moved) is considered a bug, a mistake of the caller. Caller of this method should ensure + * that this method is invoked ONLY when the temp file is created and moving it to its final place is + * required. + */ + void move() throws IOException; + } + + /** + * Creates a {@link TempFile} instance and backing temporary file on file system. It will be located in the default + * temporary-file directory. Returned instance should be handled in try-with-resource construct and created + * temp file is removed (if exists) when returned instance is closed. + *

+ * This method uses {@link Files#createTempFile(String, String, java.nio.file.attribute.FileAttribute[])} to create + * the temporary file on file system. + * + * @since 2.0.13 + */ + TempFile newTempFile() throws IOException; + + /** + * Creates a {@link CollocatedTempFile} instance for given file without backing file. The path will be located in + * same directory where given file is, and will reuse its name for generated (randomized) name. Returned instance + * should be handled in try-with-resource and created temp path is removed (if exists) when returned instance is + * closed. The {@link CollocatedTempFile#move()} makes possible to atomically replace passed in file with the + * processed content written into a file backing the {@link CollocatedTempFile} instance. + *

+ * The {@code file} nor it's parent directories have to exist. The parent directories are created if needed. + *

+ * This method uses {@link Path#resolve(String)} to create the temporary file path in passed in file parent + * directory, but it does NOT create backing file on file system. + * + * @since 2.0.13 + */ + CollocatedTempFile newTempFile(Path file) throws IOException; } diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/PathProcessorSupport.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/PathProcessorSupport.java new file mode 100644 index 000000000..b484ba9bc --- /dev/null +++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/PathProcessorSupport.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.eclipse.aether.spi.io; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.AccessDeniedException; +import java.nio.file.FileSystemException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.FileTime; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicBoolean; + +import static java.util.Objects.requireNonNull; + +/** + * Utility class serving as base of {@link PathProcessor} implementations. This class can be extended or replaced + * (as component) when needed. Also, this class is published in Resolver implementation for path processor interface. + * + * @since 2.0.13 + */ +public class PathProcessorSupport implements PathProcessor { + /** + * Logic borrowed from Commons-Lang3: we really need only this, to decide do we NIO2 file ops or not. + * For some reason non-NIO2 works better on Windows. + */ + protected static final boolean IS_WINDOWS = + System.getProperty("os.name", "unknown").startsWith("Windows"); + + /** + * Escape hatch if atomic move is not desired on system we run on. + */ + protected static final boolean ATOMIC_MOVE = + Boolean.parseBoolean(System.getProperty(PathProcessor.class.getName() + "ATOMIC_MOVE", "true")); + + @Override + public boolean setLastModified(Path path, long value) throws IOException { + try { + Files.setLastModifiedTime(path, FileTime.fromMillis(value)); + return true; + } catch (FileSystemException e) { + // MRESOLVER-536: Java uses generic FileSystemException for some weird cases, + // but some subclasses like AccessDeniedEx should be re-thrown + if (e instanceof AccessDeniedException) { + throw e; + } + return false; + } + } + + @Override + public void write(Path target, String data) throws IOException { + writeFile(target, p -> Files.write(p, data.getBytes(StandardCharsets.UTF_8)), false); + } + + @Override + public void write(Path target, InputStream source) throws IOException { + writeFile(target, p -> Files.copy(source, p, StandardCopyOption.REPLACE_EXISTING), false); + } + + @Override + public void writeWithBackup(Path target, String data) throws IOException { + writeFile(target, p -> Files.write(p, data.getBytes(StandardCharsets.UTF_8)), true); + } + + @Override + public void writeWithBackup(Path target, InputStream source) throws IOException { + writeFile(target, p -> Files.copy(source, p, StandardCopyOption.REPLACE_EXISTING), true); + } + + /** + * A file writer, that accepts a {@link Path} to write some content to. Note: the file denoted by path may exist, + * hence implementation have to ensure it is able to achieve its goal ("replace existing" option or equivalent + * should be used). + */ + @FunctionalInterface + public interface FileWriter { + void write(Path path) throws IOException; + } + + /** + * Utility method to write out file to disk in "atomic" manner, with optional backups (".bak") if needed. This + * ensures that no other thread or process will be able to read not fully written files. Finally, this method + * may create the needed parent directories, if the passed in target parents does not exist. + * + * @param target that is the target file (must be an existing or non-existing file, the path must have parent) + * @param writer the writer that will accept a {@link Path} to write content to + * @param doBackup if {@code true}, and target file is about to be overwritten, a ".bak" file with old contents will + * be created/overwritten + * @throws IOException if at any step IO problem occurs + */ + public void writeFile(Path target, FileWriter writer, boolean doBackup) throws IOException { + requireNonNull(target, "target is null"); + requireNonNull(writer, "writer is null"); + Path parent = requireNonNull(target.getParent(), "target must have parent"); + + try (CollocatedTempFile tempFile = newTempFile(target)) { + writer.write(tempFile.getPath()); + if (doBackup && Files.isRegularFile(target)) { + Files.copy(target, parent.resolve(target.getFileName() + ".bak"), StandardCopyOption.REPLACE_EXISTING); + } + tempFile.move(); + } + } + + @Override + public long copy(Path source, Path target, ProgressListener listener) throws IOException { + try (InputStream in = new BufferedInputStream(Files.newInputStream(source)); + CollocatedTempFile tempTarget = newTempFile(target); + OutputStream out = new BufferedOutputStream(Files.newOutputStream(tempTarget.getPath()))) { + long result = copy(out, in, listener); + tempTarget.move(); + return result; + } + } + + private long copy(OutputStream os, InputStream is, ProgressListener listener) throws IOException { + long total = 0L; + byte[] buffer = new byte[1024 * 32]; + while (true) { + int bytes = is.read(buffer); + if (bytes < 0) { + break; + } + + os.write(buffer, 0, bytes); + + total += bytes; + + if (listener != null && bytes > 0) { + try { + listener.progressed(ByteBuffer.wrap(buffer, 0, bytes)); + } catch (Exception e) { + // too bad + } + } + } + + return total; + } + + @Override + public void move(Path source, Path target) throws IOException { + final StandardCopyOption[] copyOption = ATOMIC_MOVE + ? new StandardCopyOption[] { + StandardCopyOption.ATOMIC_MOVE, + StandardCopyOption.REPLACE_EXISTING, + StandardCopyOption.COPY_ATTRIBUTES + } + : new StandardCopyOption[] {StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES}; + if (IS_WINDOWS) { + classicCopy(source, target); + } else { + Files.move(source, target, copyOption); + } + Files.deleteIfExists(source); + } + + // Temp files + + @Override + public TempFile newTempFile() throws IOException { + Path tempFile = Files.createTempFile("resolver", "tmp"); + return new TempFile() { + @Override + public Path getPath() { + return tempFile; + } + + @Override + public void close() throws IOException { + Files.deleteIfExists(tempFile); + } + }; + } + + @Override + public CollocatedTempFile newTempFile(Path file) throws IOException { + Path parent = requireNonNull(file.getParent(), "file must have parent"); + Files.createDirectories(parent); + Path tempFile = parent.resolve(file.getFileName() + "." + + Long.toUnsignedString(ThreadLocalRandom.current().nextLong()) + ".tmp"); + return new CollocatedTempFile() { + private final AtomicBoolean wantsMove = new AtomicBoolean(false); + private final StandardCopyOption[] copyOption = ATOMIC_MOVE + ? new StandardCopyOption[] {StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING} + : new StandardCopyOption[] {StandardCopyOption.REPLACE_EXISTING}; + + @Override + public Path getPath() { + return tempFile; + } + + @Override + public void move() { + wantsMove.set(true); + } + + @Override + public void close() throws IOException { + if (wantsMove.get()) { + if (IS_WINDOWS) { + classicCopy(tempFile, file); + } else { + Files.move(tempFile, file, copyOption); + } + } + Files.deleteIfExists(tempFile); + } + }; + } + + /** + * On Windows we use pre-NIO2 way to copy files, as for some reason it works. Beat me why. + */ + protected void classicCopy(Path source, Path target) throws IOException { + ByteBuffer buffer = ByteBuffer.allocate(1024 * 32); + byte[] array = buffer.array(); + try (InputStream is = Files.newInputStream(source); + OutputStream os = Files.newOutputStream(target)) { + while (true) { + int bytes = is.read(array); + if (bytes < 0) { + break; + } + os.write(array, 0, bytes); + } + } + } +} diff --git a/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java b/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java index 9b0acb4a1..13219cefe 100644 --- a/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java +++ b/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java @@ -519,7 +519,7 @@ protected Map createRemoteRepositoryFilter HashMap result = new HashMap<>(); result.put( GroupIdRemoteRepositoryFilterSource.NAME, - new GroupIdRemoteRepositoryFilterSource(getRepositorySystemLifecycle())); + new GroupIdRemoteRepositoryFilterSource(getRepositorySystemLifecycle(), getPathProcessor())); result.put( PrefixesRemoteRepositoryFilterSource.NAME, new PrefixesRemoteRepositoryFilterSource( @@ -586,7 +586,8 @@ protected Map createTrustedChecksumsSources() { new SparseDirectoryTrustedChecksumsSource(getChecksumProcessor(), getLocalPathComposer())); result.put( SummaryFileTrustedChecksumsSource.NAME, - new SummaryFileTrustedChecksumsSource(getLocalPathComposer(), getRepositorySystemLifecycle())); + new SummaryFileTrustedChecksumsSource( + getLocalPathComposer(), getRepositorySystemLifecycle(), getPathProcessor())); return result; } @@ -687,6 +688,7 @@ protected BasicRepositoryConnectorFactory createBasicRepositoryConnectorFactory( getTransporterProvider(), getRepositoryLayoutProvider(), getChecksumPolicyProvider(), + getPathProcessor(), getChecksumProcessor(), getProvidedChecksumsSources()); } diff --git a/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java b/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java index 94f61ae8a..e10661488 100644 --- a/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java +++ b/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java @@ -523,7 +523,7 @@ protected Map createRemoteRepositoryFilter HashMap result = new HashMap<>(); result.put( GroupIdRemoteRepositoryFilterSource.NAME, - new GroupIdRemoteRepositoryFilterSource(getRepositorySystemLifecycle())); + new GroupIdRemoteRepositoryFilterSource(getRepositorySystemLifecycle(), getPathProcessor())); result.put( PrefixesRemoteRepositoryFilterSource.NAME, new PrefixesRemoteRepositoryFilterSource( @@ -590,7 +590,8 @@ protected Map createTrustedChecksumsSources() { new SparseDirectoryTrustedChecksumsSource(getChecksumProcessor(), getLocalPathComposer())); result.put( SummaryFileTrustedChecksumsSource.NAME, - new SummaryFileTrustedChecksumsSource(getLocalPathComposer(), getRepositorySystemLifecycle())); + new SummaryFileTrustedChecksumsSource( + getLocalPathComposer(), getRepositorySystemLifecycle(), getPathProcessor())); return result; } @@ -691,6 +692,7 @@ protected BasicRepositoryConnectorFactory createBasicRepositoryConnectorFactory( getTransporterProvider(), getRepositoryLayoutProvider(), getChecksumPolicyProvider(), + getPathProcessor(), getChecksumProcessor(), getProvidedChecksumsSources()); } diff --git a/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestPathProcessor.java b/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestPathProcessor.java index b18eafbd8..e282d2860 100644 --- a/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestPathProcessor.java +++ b/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestPathProcessor.java @@ -18,46 +18,12 @@ */ package org.eclipse.aether.internal.test.util; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.FileTime; - -import org.eclipse.aether.spi.io.PathProcessor; +import org.eclipse.aether.spi.io.PathProcessorSupport; /** * A simple file processor implementation to help satisfy component requirements during tests. + * + * @deprecated This class is deprecated and is unused in Resolver. Use {@link PathProcessorSupport} instead. */ -public class TestPathProcessor implements PathProcessor { - - private final TestFileProcessor testFileProcessor = new TestFileProcessor(); - - @Override - public void setLastModified(Path path, long value) throws IOException { - Files.setLastModifiedTime(path, FileTime.fromMillis(value)); - } - - public void mkdirs(Path directory) { - if (directory == null) { - return; - } - testFileProcessor.mkdirs(directory.toFile()); - } - - public void write(Path file, String data) throws IOException { - testFileProcessor.write(file.toFile(), data); - } - - public void write(Path target, InputStream source) throws IOException { - testFileProcessor.write(target.toFile(), source); - } - - public long copy(Path source, Path target, ProgressListener listener) throws IOException { - return testFileProcessor.copy(source.toFile(), target.toFile(), null); - } - - public void move(Path source, Path target) throws IOException { - testFileProcessor.move(source.toFile(), target.toFile()); - } -} +@Deprecated +public class TestPathProcessor extends PathProcessorSupport {} diff --git a/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/ApacheTransporter.java b/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/ApacheTransporter.java index 77776a435..3084c2ad7 100644 --- a/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/ApacheTransporter.java +++ b/maven-resolver-transport-apache/src/main/java/org/eclipse/aether/transport/apache/ApacheTransporter.java @@ -100,7 +100,6 @@ import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.transfer.TransferCancelledException; import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -683,7 +682,7 @@ public void handle(CloseableHttpResponse response) throws IOException, TransferC extractChecksums(response); } } else { - try (FileUtils.CollocatedTempFile tempFile = FileUtils.newTempFile(dataFile)) { + try (PathProcessor.CollocatedTempFile tempFile = pathProcessor.newTempFile(dataFile)) { task.setDataPath(tempFile.getPath(), resume); if (resume && Files.isRegularFile(dataFile)) { try (InputStream inputStream = Files.newInputStream(dataFile)) { diff --git a/maven-resolver-transport-apache/src/test/java/org/eclipse/aether/transport/apache/ApacheTransporterTest.java b/maven-resolver-transport-apache/src/test/java/org/eclipse/aether/transport/apache/ApacheTransporterTest.java index bc7980c52..027d605cd 100644 --- a/maven-resolver-transport-apache/src/test/java/org/eclipse/aether/transport/apache/ApacheTransporterTest.java +++ b/maven-resolver-transport-apache/src/test/java/org/eclipse/aether/transport/apache/ApacheTransporterTest.java @@ -27,11 +27,11 @@ import org.eclipse.aether.ConfigurationProperties; import org.eclipse.aether.DefaultRepositoryCache; import org.eclipse.aether.internal.test.util.TestFileUtils; -import org.eclipse.aether.internal.test.util.TestPathProcessor; import org.eclipse.aether.internal.test.util.http.HttpTransporterTest; import org.eclipse.aether.internal.test.util.http.RecordingTransportListener; import org.eclipse.aether.spi.connector.transport.GetTask; import org.eclipse.aether.spi.connector.transport.PutTask; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -44,7 +44,7 @@ class ApacheTransporterTest extends HttpTransporterTest { public ApacheTransporterTest() { - super(() -> new ApacheTransporterFactory(standardChecksumExtractor(), new TestPathProcessor())); + super(() -> new ApacheTransporterFactory(standardChecksumExtractor(), new PathProcessorSupport())); } @Override diff --git a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporter.java b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporter.java index c55ff5557..7029762e8 100644 --- a/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporter.java +++ b/maven-resolver-transport-jdk-parent/maven-resolver-transport-jdk-11/src/main/java/org/eclipse/aether/transport/jdk/JdkTransporter.java @@ -76,7 +76,6 @@ import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -335,7 +334,7 @@ protected void implGet(GetTask task) throws Exception { utilGet(task, is, true, length, downloadResumed); } } else { - try (FileUtils.CollocatedTempFile tempFile = FileUtils.newTempFile(dataFile)) { + try (PathProcessor.CollocatedTempFile tempFile = pathProcessor.newTempFile(dataFile)) { task.setDataPath(tempFile.getPath(), downloadResumed); if (downloadResumed && Files.isRegularFile(dataFile)) { try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(dataFile))) { @@ -395,7 +394,7 @@ protected void implPut(PutTask task) throws Exception { request = request.expectContinue(expectContinue); } headers.forEach(request::setHeader); - try (FileUtils.TempFile tempFile = FileUtils.newTempFile()) { + try (PathProcessor.TempFile tempFile = pathProcessor.newTempFile()) { utilPut(task, Files.newOutputStream(tempFile.getPath()), true); request.PUT(HttpRequest.BodyPublishers.ofFile(tempFile.getPath())); diff --git a/maven-resolver-transport-jetty/src/main/java/org/eclipse/aether/transport/jetty/JettyTransporter.java b/maven-resolver-transport-jetty/src/main/java/org/eclipse/aether/transport/jetty/JettyTransporter.java index c7c300a55..a4fc66885 100644 --- a/maven-resolver-transport-jetty/src/main/java/org/eclipse/aether/transport/jetty/JettyTransporter.java +++ b/maven-resolver-transport-jetty/src/main/java/org/eclipse/aether/transport/jetty/JettyTransporter.java @@ -55,7 +55,6 @@ import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.transfer.TransferCancelledException; import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.FileUtils; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpProxy; import org.eclipse.jetty.client.api.Authentication; @@ -315,7 +314,7 @@ protected void implGet(GetTask task) throws Exception { utilGet(task, is, true, length, downloadResumed); } } else { - try (FileUtils.CollocatedTempFile tempFile = FileUtils.newTempFile(dataFile)) { + try (PathProcessor.CollocatedTempFile tempFile = pathProcessor.newTempFile(dataFile)) { task.setDataPath(tempFile.getPath(), downloadResumed); if (downloadResumed && Files.isRegularFile(dataFile)) { try (InputStream inputStream = Files.newInputStream(dataFile)) { diff --git a/maven-resolver-transport-jetty/src/test/java/org/eclipse/aether/transport/jetty/JettyTransporterTest.java b/maven-resolver-transport-jetty/src/test/java/org/eclipse/aether/transport/jetty/JettyTransporterTest.java index 67b3c976f..ec9af47c2 100644 --- a/maven-resolver-transport-jetty/src/test/java/org/eclipse/aether/transport/jetty/JettyTransporterTest.java +++ b/maven-resolver-transport-jetty/src/test/java/org/eclipse/aether/transport/jetty/JettyTransporterTest.java @@ -18,8 +18,8 @@ */ package org.eclipse.aether.transport.jetty; -import org.eclipse.aether.internal.test.util.TestPathProcessor; import org.eclipse.aether.internal.test.util.http.HttpTransporterTest; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -59,6 +59,6 @@ protected void testRetryHandler_explicitCount_positive() {} protected void testPut_Authenticated_ExpectContinueRejected_ExplicitlyConfiguredHeader() {} public JettyTransporterTest() { - super(() -> new JettyTransporterFactory(standardChecksumExtractor(), new TestPathProcessor())); + super(() -> new JettyTransporterFactory(standardChecksumExtractor(), new PathProcessorSupport())); } } diff --git a/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporter.java b/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporter.java index 3299ec1ed..8566e07f9 100644 --- a/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporter.java +++ b/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporter.java @@ -44,9 +44,11 @@ import org.eclipse.aether.spi.connector.transport.PeekTask; import org.eclipse.aether.spi.connector.transport.PutTask; import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.FileUtils; + +import static java.util.Objects.requireNonNull; /** * A transporter for S3 backed by MinIO Java. @@ -62,10 +64,13 @@ final class MinioTransporter extends AbstractTransporter implements Transporter private final ObjectNameMapper objectNameMapper; + private final PathProcessor pathProcessor; + MinioTransporter( RepositorySystemSession session, RemoteRepository repository, - ObjectNameMapperFactory objectNameMapperFactory) + ObjectNameMapperFactory objectNameMapperFactory, + PathProcessor pathProcessor) throws NoTransporterException { try { URI uri = new URI(repository.getUrl()).parseServerAuthority(); @@ -121,6 +126,7 @@ final class MinioTransporter extends AbstractTransporter implements Transporter .credentialsProvider(credentialsProvider) .build(); this.objectNameMapper = objectNameMapperFactory.create(session, repository, client, headers); + this.pathProcessor = requireNonNull(pathProcessor); } @Override @@ -158,7 +164,7 @@ protected void implGet(GetTask task) throws Exception { if (dataFile == null) { utilGet(task, stream, true, -1, false); } else { - try (FileUtils.CollocatedTempFile tempFile = FileUtils.newTempFile(dataFile)) { + try (PathProcessor.CollocatedTempFile tempFile = pathProcessor.newTempFile(dataFile)) { task.setDataPath(tempFile.getPath(), false); utilGet(task, stream, true, -1, false); tempFile.move(); @@ -176,7 +182,7 @@ protected void implPut(PutTask task) throws Exception { task.getListener().transportStarted(0, task.getDataLength()); final Path dataFile = task.getDataPath(); if (dataFile == null) { - try (FileUtils.TempFile tempFile = FileUtils.newTempFile()) { + try (PathProcessor.TempFile tempFile = pathProcessor.newTempFile()) { Files.copy(task.newInputStream(), tempFile.getPath(), StandardCopyOption.REPLACE_EXISTING); client.uploadObject(UploadObjectArgs.builder() .bucket(objectName.getBucket()) diff --git a/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporterFactory.java b/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporterFactory.java index c5240f533..1f1851772 100644 --- a/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporterFactory.java +++ b/maven-resolver-transport-minio/src/main/java/org/eclipse/aether/transport/minio/MinioTransporterFactory.java @@ -27,6 +27,7 @@ import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.spi.connector.transport.Transporter; import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.util.ConfigUtils; @@ -47,9 +48,13 @@ public final class MinioTransporterFactory implements TransporterFactory { private final Map objectNameMapperFactories; + private final PathProcessor pathProcessor; + @Inject - public MinioTransporterFactory(Map objectNameMapperFactories) { + public MinioTransporterFactory( + Map objectNameMapperFactories, PathProcessor pathProcessor) { this.objectNameMapperFactories = requireNonNull(objectNameMapperFactories, "objectNameMapperFactories"); + this.pathProcessor = requireNonNull(pathProcessor, "pathProcessor"); } @Override @@ -96,6 +101,6 @@ public Transporter newInstance(RepositorySystemSession session, RemoteRepository throw new IllegalArgumentException("Unknown object name mapper configured '" + objectNameMapperConf + "' for repository " + repository.getId()); } - return new MinioTransporter(session, adjusted, objectNameMapperFactory); + return new MinioTransporter(session, adjusted, objectNameMapperFactory, pathProcessor); } } diff --git a/maven-resolver-transport-minio/src/test/java/org/eclipse/aether/transport/minio/MinioTransporterFactoryTest.java b/maven-resolver-transport-minio/src/test/java/org/eclipse/aether/transport/minio/MinioTransporterFactoryTest.java index 7ce8d2354..b2c3c83d0 100644 --- a/maven-resolver-transport-minio/src/test/java/org/eclipse/aether/transport/minio/MinioTransporterFactoryTest.java +++ b/maven-resolver-transport-minio/src/test/java/org/eclipse/aether/transport/minio/MinioTransporterFactoryTest.java @@ -28,6 +28,7 @@ import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.transport.minio.internal.FixedBucketObjectNameMapperFactory; import org.eclipse.aether.transport.minio.internal.RepositoryIdObjectNameMapperFactory; @@ -55,7 +56,7 @@ void startSuite() throws Exception { factories.put(RepositoryIdObjectNameMapperFactory.NAME, new RepositoryIdObjectNameMapperFactory()); factories.put(FixedBucketObjectNameMapperFactory.NAME, new FixedBucketObjectNameMapperFactory()); - factory = new MinioTransporterFactory(factories); + factory = new MinioTransporterFactory(factories, new PathProcessorSupport()); session = new DefaultRepositorySystemSession(h -> true); repository = new RemoteRepository.Builder("repo", "default", "minio+http://localhost") .setAuthentication(new AuthenticationBuilder() diff --git a/maven-resolver-transport-minio/src/test/java/org/eclipse/aether/transport/minio/MinioTransporterIT.java b/maven-resolver-transport-minio/src/test/java/org/eclipse/aether/transport/minio/MinioTransporterIT.java index 1547bd639..4760e6ae8 100644 --- a/maven-resolver-transport-minio/src/test/java/org/eclipse/aether/transport/minio/MinioTransporterIT.java +++ b/maven-resolver-transport-minio/src/test/java/org/eclipse/aether/transport/minio/MinioTransporterIT.java @@ -34,9 +34,10 @@ import org.eclipse.aether.spi.connector.transport.PeekTask; import org.eclipse.aether.spi.connector.transport.PutTask; import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.io.PathProcessor; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.transport.minio.internal.RepositoryIdObjectNameMapperFactory; -import org.eclipse.aether.util.FileUtils; import org.eclipse.aether.util.repository.AuthenticationBuilder; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -58,6 +59,7 @@ class MinioTransporterIT { private static final String OBJECT_NAME = "dir/file.txt"; private static final String OBJECT_CONTENT = "content"; + private PathProcessor pathProcessor; private MinIOContainer minioContainer; private RepositorySystemSession session; private ObjectNameMapperFactory objectNameMapperFactory; @@ -66,6 +68,7 @@ class MinioTransporterIT { void startSuite() throws Exception { Files.createDirectories(Paths.get(System.getProperty("java.io.tmpdir"))); // hack for Surefire + pathProcessor = new PathProcessorSupport(); minioContainer = new MinIOContainer("minio/minio:latest"); minioContainer.start(); try (MinioClient minioClient = MinioClient.builder() @@ -73,7 +76,7 @@ void startSuite() throws Exception { .credentials(minioContainer.getUserName(), minioContainer.getPassword()) .build()) { minioClient.makeBucket(MakeBucketArgs.builder().bucket(BUCKET_NAME).build()); - try (FileUtils.TempFile tempFile = FileUtils.newTempFile()) { + try (PathProcessor.TempFile tempFile = pathProcessor.newTempFile()) { Files.write(tempFile.getPath(), OBJECT_CONTENT.getBytes(StandardCharsets.UTF_8)); minioClient.uploadObject(UploadObjectArgs.builder() .bucket(BUCKET_NAME) @@ -118,7 +121,7 @@ protected RemoteRepository newRepo(RepositoryAuth auth) { @Test void peekWithoutAuth() throws NoTransporterException { try { - new MinioTransporter(session, newRepo(RepositoryAuth.WITHOUT), objectNameMapperFactory); + new MinioTransporter(session, newRepo(RepositoryAuth.WITHOUT), objectNameMapperFactory, pathProcessor); fail("Should throw"); } catch (IllegalStateException e) { assertTrue(e.getMessage().contains("No accessKey and/or secretKey provided")); @@ -128,7 +131,7 @@ void peekWithoutAuth() throws NoTransporterException { @Test void peekWithWrongAuth() throws NoTransporterException { try (MinioTransporter transporter = - new MinioTransporter(session, newRepo(RepositoryAuth.WRONG), objectNameMapperFactory)) { + new MinioTransporter(session, newRepo(RepositoryAuth.WRONG), objectNameMapperFactory, pathProcessor)) { try { transporter.peek(new PeekTask(URI.create("test"))); fail("Should throw"); @@ -142,7 +145,7 @@ void peekWithWrongAuth() throws NoTransporterException { @Test void peekNonexistent() throws NoTransporterException { try (MinioTransporter transporter = - new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory)) { + new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory, pathProcessor)) { try { transporter.peek(new PeekTask(URI.create("test"))); fail("Should throw"); @@ -156,7 +159,7 @@ void peekNonexistent() throws NoTransporterException { @Test void peekExistent() throws Exception { try (MinioTransporter transporter = - new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory)) { + new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory, pathProcessor)) { transporter.peek(new PeekTask(URI.create(OBJECT_NAME))); // Should not throw } @@ -165,7 +168,7 @@ void peekExistent() throws Exception { @Test void getNonexistent() throws NoTransporterException { try (MinioTransporter transporter = - new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory)) { + new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory, pathProcessor)) { try { transporter.get(new GetTask(URI.create("test"))); fail("Should throw"); @@ -179,7 +182,7 @@ void getNonexistent() throws NoTransporterException { @Test void getExistent() throws Exception { try (MinioTransporter transporter = - new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory)) { + new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory, pathProcessor)) { GetTask task = new GetTask(URI.create(OBJECT_NAME)); transporter.get(task); assertEquals(OBJECT_CONTENT, new String(task.getDataBytes(), StandardCharsets.UTF_8)); @@ -189,7 +192,7 @@ void getExistent() throws Exception { @Test void putNonexistent() throws Exception { try (MinioTransporter transporter = - new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory)) { + new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory, pathProcessor)) { URI uri = URI.create("test"); transporter.put(new PutTask(uri).setDataBytes(OBJECT_CONTENT.getBytes(StandardCharsets.UTF_8))); GetTask task = new GetTask(uri); @@ -201,7 +204,7 @@ void putNonexistent() throws Exception { @Test void putExistent() throws Exception { try (MinioTransporter transporter = - new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory)) { + new MinioTransporter(session, newRepo(RepositoryAuth.WITH), objectNameMapperFactory, pathProcessor)) { URI uri = URI.create(OBJECT_NAME); GetTask task = new GetTask(uri); transporter.get(task); diff --git a/maven-resolver-transport-wagon/pom.xml b/maven-resolver-transport-wagon/pom.xml index 3b5b4133c..d8c55463e 100644 --- a/maven-resolver-transport-wagon/pom.xml +++ b/maven-resolver-transport-wagon/pom.xml @@ -86,6 +86,11 @@ maven-resolver-test-util test + + org.apache.maven.resolver + maven-resolver-impl + test + org.codehaus.plexus plexus-testing diff --git a/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java b/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java index 201a82b0c..107f2b8d2 100644 --- a/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java +++ b/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporter.java @@ -53,9 +53,9 @@ import org.eclipse.aether.spi.connector.transport.PutTask; import org.eclipse.aether.spi.connector.transport.TransportTask; import org.eclipse.aether.spi.connector.transport.Transporter; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.util.ConfigUtils; -import org.eclipse.aether.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -75,6 +75,8 @@ final class WagonTransporter implements Transporter { private final RepositorySystemSession session; + private final PathProcessor pathProcessor; + private final AuthenticationContext repoAuthContext; private final AuthenticationContext proxyAuthContext; @@ -101,12 +103,14 @@ final class WagonTransporter implements Transporter { WagonProvider wagonProvider, WagonConfigurator wagonConfigurator, RemoteRepository repository, - RepositorySystemSession session) + RepositorySystemSession session, + PathProcessor pathProcessor) throws NoTransporterException { this.wagonProvider = wagonProvider; this.wagonConfigurator = wagonConfigurator; this.repository = repository; this.session = session; + this.pathProcessor = pathProcessor; wagonRepo = new Repository(repository.getId(), repository.getUrl()); wagonRepo.setPermissions(getPermissions(repository.getId(), session)); @@ -340,12 +344,12 @@ public void peek(PeekTask task) throws Exception { @Override public void get(GetTask task) throws Exception { - execute(task, new GetTaskRunner(task)); + execute(task, new GetTaskRunner(pathProcessor, task)); } @Override public void put(PutTask task) throws Exception { - execute(task, new PutTaskRunner(task)); + execute(task, new PutTaskRunner(pathProcessor, task)); } private void execute(TransportTask task, TaskRunner runner) throws Exception { @@ -407,9 +411,12 @@ public void run(Wagon wagon) throws WagonException { private static class GetTaskRunner implements TaskRunner { + private final PathProcessor pathProcessor; + private final GetTask task; - GetTaskRunner(GetTask task) { + GetTaskRunner(PathProcessor pathProcessor, GetTask task) { + this.pathProcessor = pathProcessor; this.task = task; } @@ -423,8 +430,8 @@ public void run(Wagon wagon) throws IOException, WagonException { } } else { // if file == null -> $TMP used, otherwise we place tmp file next to file - try (FileUtils.TempFile tempFile = - file == null ? FileUtils.newTempFile() : FileUtils.newTempFile(file.toPath())) { + try (PathProcessor.TempFile tempFile = + file == null ? pathProcessor.newTempFile() : pathProcessor.newTempFile(file.toPath())) { File dst = tempFile.getPath().toFile(); wagon.get(src, dst); /* @@ -437,7 +444,7 @@ public void run(Wagon wagon) throws IOException, WagonException { } if (file != null) { - ((FileUtils.CollocatedTempFile) tempFile).move(); + ((PathProcessor.CollocatedTempFile) tempFile).move(); } else { try (OutputStream outputStream = task.newOutputStream()) { Files.copy(dst.toPath(), outputStream); @@ -450,9 +457,12 @@ public void run(Wagon wagon) throws IOException, WagonException { private static class PutTaskRunner implements TaskRunner { + private final PathProcessor pathProcessor; + private final PutTask task; - PutTaskRunner(PutTask task) { + PutTaskRunner(PathProcessor pathProcessor, PutTask task) { + this.pathProcessor = pathProcessor; this.task = task; } @@ -466,7 +476,7 @@ public void run(Wagon wagon) throws WagonException, IOException { ((StreamingWagon) wagon).putFromStream(src, dst, task.getDataLength(), -1); } } else if (file == null) { - try (FileUtils.TempFile tempFile = FileUtils.newTempFile()) { + try (PathProcessor.TempFile tempFile = pathProcessor.newTempFile()) { try (InputStream inputStream = task.newInputStream()) { Files.copy(inputStream, tempFile.getPath(), StandardCopyOption.REPLACE_EXISTING); } diff --git a/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporterFactory.java b/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporterFactory.java index b6393d6dc..1958e603f 100644 --- a/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporterFactory.java +++ b/maven-resolver-transport-wagon/src/main/java/org/eclipse/aether/transport/wagon/WagonTransporterFactory.java @@ -25,6 +25,7 @@ import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.spi.connector.transport.Transporter; import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.transfer.NoTransporterException; import static java.util.Objects.requireNonNull; @@ -42,12 +43,16 @@ public final class WagonTransporterFactory implements TransporterFactory { private final WagonConfigurator wagonConfigurator; + private final PathProcessor pathProcessor; + private float priority = -1.0f; @Inject - public WagonTransporterFactory(WagonProvider wagonProvider, WagonConfigurator wagonConfigurator) { + public WagonTransporterFactory( + WagonProvider wagonProvider, WagonConfigurator wagonConfigurator, PathProcessor pathProcessor) { this.wagonProvider = wagonProvider; this.wagonConfigurator = wagonConfigurator; + this.pathProcessor = pathProcessor; } @Override @@ -72,6 +77,6 @@ public Transporter newInstance(RepositorySystemSession session, RemoteRepository requireNonNull(session, "session cannot be null"); requireNonNull(repository, "repository cannot be null"); - return new WagonTransporter(wagonProvider, wagonConfigurator, repository, session); + return new WagonTransporter(wagonProvider, wagonConfigurator, repository, session, pathProcessor); } } diff --git a/maven-resolver-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/AbstractWagonTransporterTest.java b/maven-resolver-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/AbstractWagonTransporterTest.java index 9d002c00a..b4c048fbc 100644 --- a/maven-resolver-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/AbstractWagonTransporterTest.java +++ b/maven-resolver-transport-wagon/src/test/java/org/eclipse/aether/transport/wagon/AbstractWagonTransporterTest.java @@ -39,6 +39,7 @@ import org.eclipse.aether.spi.connector.transport.PutTask; import org.eclipse.aether.spi.connector.transport.Transporter; import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.io.PathProcessorSupport; import org.eclipse.aether.transfer.NoTransporterException; import org.eclipse.aether.transfer.TransferCancelledException; import org.eclipse.aether.util.repository.AuthenticationBuilder; @@ -99,7 +100,8 @@ public void release(Wagon wagon) {} public void configure(Wagon wagon, Object configuration) { ((Configurable) wagon).setConfiguration(configuration); } - }); + }, + new PathProcessorSupport()); id = UUID.randomUUID().toString().replace("-", ""); fs = MemWagonUtils.getFilesystem(id); fs.put("file.txt", "test"); diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/FileUtils.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/FileUtils.java index 4e4e14b13..736420762 100644 --- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/FileUtils.java +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/FileUtils.java @@ -35,7 +35,9 @@ * A utility class to write files. * * @since 1.9.0 + * @deprecated Do not use this class; is not used in Resolver (see corresponding processor components in {@code org.eclipse.aether.spi.io} package). */ +@Deprecated public final class FileUtils { /** * Logic borrowed from Commons-Lang3: we really need only this, to decide do we NIO2 file ops or not. @@ -55,6 +57,7 @@ public final class FileUtils { private FileUtils() { // hide constructor } + /** * A temporary file, that is removed when closed. */