From 443d29d3255231b0a323cb1894a7308a3b0dc30d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9da=20Housni=20Alaoui?= Date: Tue, 20 Aug 2024 10:45:47 +0200 Subject: [PATCH] Allow multiple cache entries per checksum --- .../BuildCacheMojosExecutionStrategy.java | 15 +++- .../maven/buildcache/CacheController.java | 9 +- .../maven/buildcache/CacheControllerImpl.java | 83 +++++++++++-------- .../maven/buildcache/CacheRepository.java | 6 +- .../apache/maven/buildcache/CacheResult.java | 37 ++++++--- .../DefaultProjectInputCalculator.java | 15 ++-- .../buildcache/LocalCacheRepository.java | 8 +- .../buildcache/LocalCacheRepositoryImpl.java | 65 ++++++++------- .../buildcache/ProjectInputCalculator.java | 2 +- .../buildcache/RemoteCacheRepository.java | 6 +- .../buildcache/RemoteCacheRepositoryImpl.java | 30 +++---- .../buildcache/RemoteCacheRepositoryNoOp.java | 12 +-- .../org/apache/maven/buildcache/Zone.java | 65 +++++++++++++++ .../checksum/MavenProjectInput.java | 32 +++---- .../maven/buildcache/xml/CacheConfig.java | 5 ++ .../maven/buildcache/xml/CacheConfigImpl.java | 31 +++++++ .../buildcache/its/AsymetricZonesTest.java | 74 +++++++++++++++++ .../its/IncrementalRestoreTest.java | 4 +- .../maven/buildcache/its/Issue67Test.java | 2 +- .../.mvn/maven-build-cache-config.xml | 24 ++++++ src/test/projects/asymetric-zones/pom.xml | 42 ++++++++++ .../org/apache/maven/buildcache/Test.java | 24 ++++++ 22 files changed, 452 insertions(+), 139 deletions(-) create mode 100644 src/main/java/org/apache/maven/buildcache/Zone.java create mode 100644 src/test/java/org/apache/maven/buildcache/its/AsymetricZonesTest.java create mode 100644 src/test/projects/asymetric-zones/.mvn/maven-build-cache-config.xml create mode 100644 src/test/projects/asymetric-zones/pom.xml create mode 100644 src/test/projects/asymetric-zones/src/main/java/org/apache/maven/buildcache/Test.java diff --git a/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java b/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java index 5790d19f..5eb63d50 100644 --- a/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java +++ b/src/main/java/org/apache/maven/buildcache/BuildCacheMojosExecutionStrategy.java @@ -107,6 +107,7 @@ public void execute( // execute clean bound goals before restoring to not interfere/slowdown clean CacheState cacheState = DISABLED; CacheResult result = CacheResult.empty(); + boolean restorable = false; boolean skipCache = cacheConfig.isSkipCache() || MavenProjectInput.isSkipCache(project); boolean cacheIsDisabled = MavenProjectInput.isCacheDisabled(project); // Forked execution should be thought as a part of originating mojo internal implementation @@ -125,11 +126,17 @@ public void execute( "Cache is explicitly disabled on project level for {}", getVersionlessProjectKey(project)); } if (cacheState == INITIALIZED || skipCache) { - result = cacheController.findCachedBuild(session, project, mojoExecutions, skipCache); + for (Zone zone : cacheConfig.getInputZones()) { + result = cacheController.findCachedBuild(session, project, mojoExecutions, zone, skipCache); + restorable = result.isSuccess() || result.isPartialSuccess(); + if (!restorable) { + continue; + } + break; + } } } - boolean restorable = result.isSuccess() || result.isPartialSuccess(); boolean restored = false; // if partially restored need to save increment if (restorable) { CacheRestorationStatus cacheRestorationStatus = @@ -157,7 +164,9 @@ public void execute( LOGGER.info("Cache storing is skipped since there was no \"clean\" phase."); } else { final Map executionEvents = mojoListener.getProjectExecutions(project); - cacheController.save(result, mojoExecutions, executionEvents); + for (Zone zone : cacheConfig.getOutputZones()) { + cacheController.save(result, mojoExecutions, executionEvents, zone); + } } } diff --git a/src/main/java/org/apache/maven/buildcache/CacheController.java b/src/main/java/org/apache/maven/buildcache/CacheController.java index 7acf7850..5df71563 100644 --- a/src/main/java/org/apache/maven/buildcache/CacheController.java +++ b/src/main/java/org/apache/maven/buildcache/CacheController.java @@ -33,14 +33,19 @@ public interface CacheController { CacheResult findCachedBuild( - MavenSession session, MavenProject project, List mojoExecutions, boolean skipCache); + MavenSession session, + MavenProject project, + List mojoExecutions, + Zone inputZone, + boolean skipCache); ArtifactRestorationReport restoreProjectArtifacts(CacheResult cacheResult); void save( CacheResult cacheResult, List mojoExecutions, - Map executionEvents); + Map executionEvents, + Zone outputZone); boolean isForcedExecution(MavenProject project, MojoExecution execution); diff --git a/src/main/java/org/apache/maven/buildcache/CacheControllerImpl.java b/src/main/java/org/apache/maven/buildcache/CacheControllerImpl.java index 6cc644f9..65330ce5 100644 --- a/src/main/java/org/apache/maven/buildcache/CacheControllerImpl.java +++ b/src/main/java/org/apache/maven/buildcache/CacheControllerImpl.java @@ -168,7 +168,11 @@ public CacheControllerImpl( @Override @Nonnull public CacheResult findCachedBuild( - MavenSession session, MavenProject project, List mojoExecutions, boolean skipCache) { + MavenSession session, + MavenProject project, + List mojoExecutions, + Zone inputZone, + boolean skipCache) { final String highestPhase = lifecyclePhasesHelper.resolveHighestLifecyclePhase(project, mojoExecutions); if (!lifecyclePhasesHelper.isLaterPhaseThanClean(highestPhase)) { @@ -177,30 +181,33 @@ public CacheResult findCachedBuild( String projectName = getVersionlessProjectKey(project); - ProjectsInputInfo inputInfo = projectInputCalculator.calculateInput(project); + ProjectsInputInfo inputInfo = projectInputCalculator.calculateInput(project, inputZone); final CacheContext context = new CacheContext(project, inputInfo, session); - CacheResult result = empty(context); + CacheResult result = empty(context, inputZone); if (!skipCache) { - LOGGER.info("Attempting to restore project {} from build cache", projectName); + LOGGER.info("Attempting to restore project {} from build cache zone {}", projectName, inputZone); // remote build first if (cacheConfig.isRemoteCacheEnabled()) { - result = findCachedBuild(mojoExecutions, context); + result = findCachedBuild(mojoExecutions, context, inputZone); if (!result.isSuccess() && result.getContext() != null) { LOGGER.info("Remote cache is incomplete or missing, trying local build for {}", projectName); } } if (!result.isSuccess() && result.getContext() != null) { - CacheResult localBuild = findLocalBuild(mojoExecutions, context); + CacheResult localBuild = findLocalBuild(mojoExecutions, context, inputZone); if (localBuild.isSuccess() || (localBuild.isPartialSuccess() && !result.isPartialSuccess())) { result = localBuild; } else { LOGGER.info( - "Local build was not found by checksum {} for {}", inputInfo.getChecksum(), projectName); + "Local build was not found by checksum {} for {} and zone {}", + inputInfo.getChecksum(), + projectName, + inputZone); } } } else { @@ -212,39 +219,43 @@ public CacheResult findCachedBuild( return result; } - private CacheResult findCachedBuild(List mojoExecutions, CacheContext context) { + private CacheResult findCachedBuild(List mojoExecutions, CacheContext context, Zone inputZone) { Optional cachedBuild = Optional.empty(); try { - cachedBuild = localCache.findBuild(context); + cachedBuild = localCache.findBuild(context, inputZone); if (cachedBuild.isPresent()) { - return analyzeResult(context, mojoExecutions, cachedBuild.get()); + return analyzeResult(context, mojoExecutions, inputZone, cachedBuild.get()); } } catch (Exception e) { LOGGER.error("Cannot read cached remote build", e); } - return cachedBuild.map(build -> failure(build, context)).orElseGet(() -> empty(context)); + return cachedBuild.map(build -> failure(build, context, inputZone)).orElseGet(() -> empty(context, inputZone)); } - private CacheResult findLocalBuild(List mojoExecutions, CacheContext context) { + private CacheResult findLocalBuild(List mojoExecutions, CacheContext context, Zone inputZone) { Optional localBuild = Optional.empty(); try { - localBuild = localCache.findLocalBuild(context); + localBuild = localCache.findLocalBuild(context, inputZone); if (localBuild.isPresent()) { - return analyzeResult(context, mojoExecutions, localBuild.get()); + return analyzeResult(context, mojoExecutions, inputZone, localBuild.get()); } } catch (Exception e) { LOGGER.error("Cannot read local build", e); } - return localBuild.map(build -> failure(build, context)).orElseGet(() -> empty(context)); + return localBuild.map(build -> failure(build, context, inputZone)).orElseGet(() -> empty(context, inputZone)); } - private CacheResult analyzeResult(CacheContext context, List mojoExecutions, Build build) { + private CacheResult analyzeResult( + CacheContext context, List mojoExecutions, Zone inputZone, Build build) { try { final ProjectsInputInfo inputInfo = context.getInputInfo(); String projectName = getVersionlessProjectKey(context.getProject()); LOGGER.info( - "Found cached build, restoring {} from cache by checksum {}", projectName, inputInfo.getChecksum()); + "Found cached build, restoring {} from cache zone {} by checksum {}", + projectName, + inputZone, + inputInfo.getChecksum()); LOGGER.debug("Cached build details: {}", build); final String cacheImplementationVersion = build.getCacheImplementationVersion(); @@ -263,12 +274,12 @@ private CacheResult analyzeResult(CacheContext context, List mojo "Cached build doesn't contains all requested plugin executions " + "(missing: {}), cannot restore", missingMojos); - return failure(build, context); + return failure(build, context, inputZone); } if (!isCachedSegmentPropertiesPresent(context.getProject(), build, cachedSegment)) { LOGGER.info("Cached build violates cache rules, cannot restore"); - return failure(build, context); + return failure(build, context, inputZone); } final String highestRequestPhase = @@ -281,15 +292,15 @@ private CacheResult analyzeResult(CacheContext context, List mojo projectName, build.getHighestCompletedGoal(), highestRequestPhase); - return partialSuccess(build, context); + return partialSuccess(build, context, inputZone); } - return success(build, context); + return success(build, context, inputZone); } catch (Exception e) { LOGGER.error("Failed to restore project", e); - localCache.clearCache(context); - return failure(build, context); + localCache.clearCache(context, inputZone); + return failure(build, context, inputZone); } } @@ -389,8 +400,8 @@ public ArtifactRestorationReport restoreProjectArtifacts(CacheResult cacheResult // Set this value before trying the restoration, to keep a trace of the attempt if it fails restorationReport.setRestoredFilesInProjectDirectory(true); // generated sources artifact - final Path attachedArtifactFile = - localCache.getArtifactFile(context, cacheResult.getSource(), attachedArtifactInfo); + final Path attachedArtifactFile = localCache.getArtifactFile( + context, cacheResult.getSource(), cacheResult.getInputZone(), attachedArtifactInfo); restoreGeneratedSources(attachedArtifactInfo, attachedArtifactFile, project); } } else { @@ -462,7 +473,8 @@ private Future createDownloadTask( String originalVersion) { final FutureTask downloadTask = new FutureTask<>(() -> { LOGGER.debug("Downloading artifact {}", artifact.getArtifactId()); - final Path artifactFile = localCache.getArtifactFile(context, cacheResult.getSource(), artifact); + final Path artifactFile = + localCache.getArtifactFile(context, cacheResult.getSource(), cacheResult.getInputZone(), artifact); if (!Files.exists(artifactFile)) { throw new FileNotFoundException("Missing file for cached build, cannot restore. File: " + artifactFile); @@ -482,7 +494,8 @@ private Future createDownloadTask( public void save( CacheResult cacheResult, List mojoExecutions, - Map executionEvents) { + Map executionEvents, + Zone outputZone) { CacheContext context = cacheResult.getContext(); if (context == null || context.getInputInfo() == null) { @@ -526,19 +539,19 @@ public void save( build.getDto().set_final(cacheConfig.isSaveToRemoteFinal()); cacheResults.put(getVersionlessProjectKey(project), rebuilded(cacheResult, build)); - localCache.beforeSave(context); + localCache.beforeSave(context, outputZone); // if package phase presence means new artifacts were packaged if (project.hasLifecyclePhase("package")) { if (projectArtifact.getFile() != null) { - localCache.saveArtifactFile(cacheResult, projectArtifact); + localCache.saveArtifactFile(cacheResult, outputZone, projectArtifact); } for (org.apache.maven.artifact.Artifact attachedArtifact : attachedArtifacts) { if (attachedArtifact.getFile() != null) { boolean storeArtifact = isOutputArtifact(attachedArtifact.getFile().getName()); if (storeArtifact) { - localCache.saveArtifactFile(cacheResult, attachedArtifact); + localCache.saveArtifactFile(cacheResult, outputZone, attachedArtifact); } else { LOGGER.debug( "Skipping attached project artifact '{}' = " @@ -549,7 +562,7 @@ public void save( } } - localCache.saveBuildInfo(cacheResult, build); + localCache.saveBuildInfo(cacheResult, outputZone, build); if (cacheConfig.isBaselineDiffEnabled()) { produceDiffReport(cacheResult, build); @@ -558,7 +571,7 @@ public void save( } catch (Exception e) { LOGGER.error("Failed to save project, cleaning cache. Project: {}", project, e); try { - localCache.clearCache(context); + localCache.clearCache(context, outputZone); } catch (Exception ex) { LOGGER.error("Failed to clean cache due to unexpected error:", ex); } @@ -567,7 +580,7 @@ public void save( public void produceDiffReport(CacheResult cacheResult, Build build) { MavenProject project = cacheResult.getContext().getProject(); - Optional baselineHolder = remoteCache.findBaselineBuild(project); + Optional baselineHolder = remoteCache.findBaselineBuild(project, cacheResult.getInputZone()); if (baselineHolder.isPresent()) { Build baseline = baselineHolder.get(); String outputDirectory = project.getBuild().getDirectory(); @@ -841,10 +854,10 @@ public void saveCacheReport(MavenSession session) { projectReport.setLifecycleMatched(checksumMatched && result.isSuccess()); projectReport.setSource(String.valueOf(result.getSource())); if (result.getSource() == CacheSource.REMOTE) { - projectReport.setUrl(remoteCache.getResourceUrl(context, BUILDINFO_XML)); + projectReport.setUrl(remoteCache.getResourceUrl(context, result.getInputZone(), BUILDINFO_XML)); } else if (result.getSource() == CacheSource.BUILD && cacheConfig.isSaveToRemote()) { projectReport.setSharedToRemote(true); - projectReport.setUrl(remoteCache.getResourceUrl(context, BUILDINFO_XML)); + projectReport.setUrl(remoteCache.getResourceUrl(context, result.getInputZone(), BUILDINFO_XML)); } cacheReport.addProject(projectReport); } diff --git a/src/main/java/org/apache/maven/buildcache/CacheRepository.java b/src/main/java/org/apache/maven/buildcache/CacheRepository.java index 6a9a2934..7779a5f1 100644 --- a/src/main/java/org/apache/maven/buildcache/CacheRepository.java +++ b/src/main/java/org/apache/maven/buildcache/CacheRepository.java @@ -34,11 +34,11 @@ public interface CacheRepository { @Nonnull - Optional findBuild(CacheContext context) throws IOException; + Optional findBuild(CacheContext context, Zone inputZone) throws IOException; - void saveBuildInfo(CacheResult cacheResult, Build build) throws IOException; + void saveBuildInfo(CacheResult cacheResult, Zone outputZone, Build build) throws IOException; - void saveArtifactFile(CacheResult cacheResult, Artifact artifact) throws IOException; + void saveArtifactFile(CacheResult cacheResult, Zone outputZone, Artifact artifact) throws IOException; void saveCacheReport(String buildId, MavenSession session, CacheReport cacheReport) throws IOException; } diff --git a/src/main/java/org/apache/maven/buildcache/CacheResult.java b/src/main/java/org/apache/maven/buildcache/CacheResult.java index e2c118b1..675a052b 100644 --- a/src/main/java/org/apache/maven/buildcache/CacheResult.java +++ b/src/main/java/org/apache/maven/buildcache/CacheResult.java @@ -31,49 +31,56 @@ public class CacheResult { private final RestoreStatus status; private final Build build; private final CacheContext context; + private final Zone inputZone; - private CacheResult(RestoreStatus status, Build build, CacheContext context) { + private CacheResult(RestoreStatus status, Build build, CacheContext context, Zone inputZone) { this.status = requireNonNull(status); this.build = build; this.context = context; + this.inputZone = inputZone; } - public static CacheResult empty(CacheContext context) { + public static CacheResult empty(CacheContext context, Zone inputZone) { requireNonNull(context); - return new CacheResult(RestoreStatus.EMPTY, null, context); + requireNonNull(inputZone); + return new CacheResult(RestoreStatus.EMPTY, null, context, inputZone); } public static CacheResult empty() { - return new CacheResult(RestoreStatus.EMPTY, null, null); + return new CacheResult(RestoreStatus.EMPTY, null, null, null); } - public static CacheResult failure(Build build, CacheContext context) { + public static CacheResult failure(Build build, CacheContext context, Zone inputZone) { requireNonNull(build); requireNonNull(context); - return new CacheResult(RestoreStatus.FAILURE, build, context); + requireNonNull(inputZone); + return new CacheResult(RestoreStatus.FAILURE, build, context, inputZone); } - public static CacheResult success(Build build, CacheContext context) { + public static CacheResult success(Build build, CacheContext context, Zone inputZone) { requireNonNull(build); requireNonNull(context); - return new CacheResult(RestoreStatus.SUCCESS, build, context); + requireNonNull(inputZone); + return new CacheResult(RestoreStatus.SUCCESS, build, context, inputZone); } - public static CacheResult partialSuccess(Build build, CacheContext context) { + public static CacheResult partialSuccess(Build build, CacheContext context, Zone inputZone) { requireNonNull(build); requireNonNull(context); - return new CacheResult(RestoreStatus.PARTIAL, build, context); + requireNonNull(inputZone); + return new CacheResult(RestoreStatus.PARTIAL, build, context, inputZone); } - public static CacheResult failure(CacheContext context) { + public static CacheResult failure(CacheContext context, Zone inputZone) { requireNonNull(context); - return new CacheResult(RestoreStatus.FAILURE, null, context); + requireNonNull(inputZone); + return new CacheResult(RestoreStatus.FAILURE, null, context, inputZone); } public static CacheResult rebuilded(CacheResult orig, Build build) { requireNonNull(orig); requireNonNull(build); - return new CacheResult(orig.status, build, orig.context); + return new CacheResult(orig.status, build, orig.context, orig.inputZone); } public boolean isSuccess() { @@ -103,4 +110,8 @@ public RestoreStatus getStatus() { public boolean isFinal() { return build != null && build.getDto().is_final(); } + + public Zone getInputZone() { + return inputZone; + } } diff --git a/src/main/java/org/apache/maven/buildcache/DefaultProjectInputCalculator.java b/src/main/java/org/apache/maven/buildcache/DefaultProjectInputCalculator.java index 3e974fc0..0f36c000 100644 --- a/src/main/java/org/apache/maven/buildcache/DefaultProjectInputCalculator.java +++ b/src/main/java/org/apache/maven/buildcache/DefaultProjectInputCalculator.java @@ -32,7 +32,6 @@ import org.apache.maven.buildcache.xml.CacheConfig; import org.apache.maven.buildcache.xml.build.ProjectsInputInfo; import org.apache.maven.execution.MavenSession; -import org.apache.maven.lifecycle.internal.builder.BuilderCommon; import org.apache.maven.project.MavenProject; import org.eclipse.aether.RepositorySystem; import org.slf4j.Logger; @@ -75,14 +74,14 @@ public DefaultProjectInputCalculator( } @Override - public ProjectsInputInfo calculateInput(MavenProject project) { + public ProjectsInputInfo calculateInput(MavenProject project, Zone inputZone) { LOGGER.info( "Going to calculate checksum for project [groupId={}, artifactId={}, version={}]", project.getGroupId(), project.getArtifactId(), project.getVersion()); - String key = BuilderCommon.getKey(project); + String key = getKey(project, inputZone); // NOTE: Do not use ConcurrentHashMap.computeIfAbsent() here because of recursive calls // this could lead to runtime exception - IllegalStateException("Recursive update") // in jdk 8 the result of attempt to modify items with the same hash code could lead to infinite loop @@ -90,12 +89,12 @@ public ProjectsInputInfo calculateInput(MavenProject project) { if (projectsInputInfo != null) { return projectsInputInfo; } - projectsInputInfo = calculateInputInternal(key, project); + projectsInputInfo = calculateInputInternal(key, project, inputZone); checkSumMap.put(key, projectsInputInfo); return projectsInputInfo; } - private ProjectsInputInfo calculateInputInternal(String key, MavenProject project) { + private ProjectsInputInfo calculateInputInternal(String key, MavenProject project, Zone inputZone) { Set projectsSet = CURRENTLY_CALCULATING.get(); if (!projectsSet.add(key)) { @@ -114,11 +113,15 @@ private ProjectsInputInfo calculateInputInternal(String key, MavenProject projec repoSystem, remoteCache, artifactHandlerManager); - return input.calculateChecksum(); + return input.calculateChecksum(inputZone); } catch (Exception e) { throw new RuntimeException("Failed to calculate checksums for " + project.getArtifactId(), e); } finally { projectsSet.remove(key); } } + + private static String getKey(MavenProject project, Zone inputZone) { + return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion() + ':' + inputZone; + } } diff --git a/src/main/java/org/apache/maven/buildcache/LocalCacheRepository.java b/src/main/java/org/apache/maven/buildcache/LocalCacheRepository.java index 3117455c..0bc8b393 100644 --- a/src/main/java/org/apache/maven/buildcache/LocalCacheRepository.java +++ b/src/main/java/org/apache/maven/buildcache/LocalCacheRepository.java @@ -35,15 +35,15 @@ */ public interface LocalCacheRepository extends CacheRepository { - void beforeSave(CacheContext environment) throws IOException; + void beforeSave(CacheContext environment, Zone outputZone) throws IOException; - Path getArtifactFile(CacheContext context, CacheSource source, Artifact artifact) throws IOException; + Path getArtifactFile(CacheContext context, CacheSource source, Zone zone, Artifact artifact) throws IOException; - void clearCache(CacheContext context); + void clearCache(CacheContext context, Zone zone); @Nonnull Optional findBestMatchingBuild(MavenSession session, Dependency dependency) throws IOException; @Nonnull - Optional findLocalBuild(CacheContext context) throws IOException; + Optional findLocalBuild(CacheContext context, Zone zone) throws IOException; } diff --git a/src/main/java/org/apache/maven/buildcache/LocalCacheRepositoryImpl.java b/src/main/java/org/apache/maven/buildcache/LocalCacheRepositoryImpl.java index dee0cf2d..df5b6f01 100644 --- a/src/main/java/org/apache/maven/buildcache/LocalCacheRepositoryImpl.java +++ b/src/main/java/org/apache/maven/buildcache/LocalCacheRepositoryImpl.java @@ -102,8 +102,8 @@ public LocalCacheRepositoryImpl( @Nonnull @Override - public Optional findLocalBuild(CacheContext context) throws IOException { - Path localBuildInfoPath = localBuildPath(context, BUILDINFO_XML, false); + public Optional findLocalBuild(CacheContext context, Zone zone) throws IOException { + Path localBuildInfoPath = localBuildPath(context, zone, BUILDINFO_XML, false); LOGGER.debug("Checking local build info: {}", localBuildInfoPath); if (Files.exists(localBuildInfoPath)) { LOGGER.info( @@ -121,8 +121,8 @@ public Optional findLocalBuild(CacheContext context) throws IOException { @Nonnull @Override - public Optional findBuild(CacheContext context) throws IOException { - Path buildInfoPath = remoteBuildPath(context, BUILDINFO_XML); + public Optional findBuild(CacheContext context, Zone inputZone) throws IOException { + Path buildInfoPath = remoteBuildPath(context, inputZone, BUILDINFO_XML); LOGGER.debug("Checking if build is already downloaded: {}", buildInfoPath); if (Files.exists(buildInfoPath)) { @@ -143,7 +143,7 @@ public Optional findBuild(CacheContext context) throws IOException { } try { - Path lookupInfoPath = remoteBuildPath(context, LOOKUPINFO_XML); + Path lookupInfoPath = remoteBuildPath(context, inputZone, LOOKUPINFO_XML); if (Files.exists(lookupInfoPath)) { final BasicFileAttributes fileAttributes = Files.readAttributes(lookupInfoPath, BasicFileAttributes.class); @@ -166,7 +166,7 @@ public Optional findBuild(CacheContext context) throws IOException { } } - final Optional build = remoteRepository.findBuild(context); + final Optional build = remoteRepository.findBuild(context, inputZone); if (build.isPresent()) { LOGGER.info("Build info downloaded from remote repo, saving to: {}", buildInfoPath); Files.createDirectories(buildInfoPath.getParent()); @@ -182,9 +182,9 @@ public Optional findBuild(CacheContext context) throws IOException { } @Override - public void clearCache(CacheContext context) { + public void clearCache(CacheContext context, Zone zone) { try { - final Path buildCacheDir = buildCacheDir(context); + final Path buildCacheDir = buildCacheDir(context, zone); Path artifactCacheDir = buildCacheDir.getParent(); if (!Files.exists(artifactCacheDir)) { @@ -206,7 +206,7 @@ public void clearCache(CacheContext context) { FileUtils.deleteDirectory(dir.toFile()); } } - final Path path = localBuildDir(context); + final Path path = localBuildDir(context, zone); if (Files.exists(path)) { FileUtils.deleteDirectory(path.toFile()); } @@ -306,13 +306,14 @@ private String getScmRef(Scm scm) { } @Override - public Path getArtifactFile(CacheContext context, CacheSource source, Artifact artifact) throws IOException { + public Path getArtifactFile(CacheContext context, CacheSource source, Zone zone, Artifact artifact) + throws IOException { if (source == CacheSource.LOCAL) { - return localBuildPath(context, artifact.getFileName(), false); + return localBuildPath(context, zone, artifact.getFileName(), false); } else { - Path cachePath = remoteBuildPath(context, artifact.getFileName()); + Path cachePath = remoteBuildPath(context, zone, artifact.getFileName()); if (!Files.exists(cachePath) && cacheConfig.isRemoteCacheEnabled()) { - if (!remoteRepository.getArtifactContent(context, artifact, cachePath)) { + if (!remoteRepository.getArtifactContent(context, zone, artifact, cachePath)) { Files.deleteIfExists(cachePath); } } @@ -321,17 +322,17 @@ public Path getArtifactFile(CacheContext context, CacheSource source, Artifact a } @Override - public void beforeSave(CacheContext environment) { - clearCache(environment); + public void beforeSave(CacheContext environment, Zone outputZone) { + clearCache(environment, outputZone); } @Override - public void saveBuildInfo(CacheResult cacheResult, Build build) throws IOException { - final Path path = localBuildPath(cacheResult.getContext(), BUILDINFO_XML, true); + public void saveBuildInfo(CacheResult cacheResult, Zone outputZone, Build build) throws IOException { + final Path path = localBuildPath(cacheResult.getContext(), outputZone, BUILDINFO_XML, true); Files.write(path, xmlService.toBytes(build.getDto()), TRUNCATE_EXISTING, CREATE); LOGGER.info("Saved Build to local file: {}", path); if (cacheConfig.isSaveToRemote() && !cacheResult.isFinal()) { - remoteRepository.saveBuildInfo(cacheResult, build); + remoteRepository.saveBuildInfo(cacheResult, outputZone, build); } } @@ -349,22 +350,23 @@ public void saveCacheReport(String buildId, MavenSession session, CacheReport ca } @Override - public void saveArtifactFile(CacheResult cacheResult, org.apache.maven.artifact.Artifact artifact) + public void saveArtifactFile(CacheResult cacheResult, Zone outputZone, org.apache.maven.artifact.Artifact artifact) throws IOException { // safe artifacts to cache File artifactFile = artifact.getFile(); - Path cachePath = localBuildPath(cacheResult.getContext(), CacheUtils.normalizedName(artifact), true); + Path cachePath = + localBuildPath(cacheResult.getContext(), outputZone, CacheUtils.normalizedName(artifact), true); Files.copy(artifactFile.toPath(), cachePath, StandardCopyOption.REPLACE_EXISTING); if (cacheConfig.isSaveToRemote() && !cacheResult.isFinal()) { - remoteRepository.saveArtifactFile(cacheResult, artifact); + remoteRepository.saveArtifactFile(cacheResult, outputZone, artifact); } } - private Path buildCacheDir(CacheContext context) throws IOException { + private Path buildCacheDir(CacheContext context, Zone zone) throws IOException { final MavenProject project = context.getProject(); final Path artifactCacheDir = artifactCacheDir(context.getSession(), project.getGroupId(), project.getArtifactId()); - return artifactCacheDir.resolve(context.getInputInfo().getChecksum()); + return artifactCacheDir.resolve(context.getInputInfo().getChecksum()).resolve(zone.value()); } private Path artifactCacheDir(MavenSession session, String groupId, String artifactId) throws IOException { @@ -385,24 +387,25 @@ private Path baseDir(MavenSession session) { } } - private Path remoteBuildPath(CacheContext context, String filename) throws IOException { - return remoteBuildDir(context).resolve(filename); + private Path remoteBuildPath(CacheContext context, Zone zone, String filename) throws IOException { + return remoteBuildDir(context, zone).resolve(filename); } - private Path localBuildPath(CacheContext context, String filename, boolean createDir) throws IOException { - final Path localBuildDir = localBuildDir(context); + private Path localBuildPath(CacheContext context, Zone zone, String filename, boolean createDir) + throws IOException { + final Path localBuildDir = localBuildDir(context, zone); if (createDir) { Files.createDirectories(localBuildDir); } return localBuildDir.resolve(filename); } - private Path remoteBuildDir(CacheContext context) throws IOException { - return buildCacheDir(context).resolve(cacheConfig.getId()); + private Path remoteBuildDir(CacheContext context, Zone zone) throws IOException { + return buildCacheDir(context, zone).resolve(cacheConfig.getId()); } - private Path localBuildDir(CacheContext context) throws IOException { - return buildCacheDir(context).resolve("local"); + private Path localBuildDir(CacheContext context, Zone zone) throws IOException { + return buildCacheDir(context, zone).resolve("local"); } private static FileTime lastModifiedTime(Path p) { diff --git a/src/main/java/org/apache/maven/buildcache/ProjectInputCalculator.java b/src/main/java/org/apache/maven/buildcache/ProjectInputCalculator.java index c7a36025..5a863281 100644 --- a/src/main/java/org/apache/maven/buildcache/ProjectInputCalculator.java +++ b/src/main/java/org/apache/maven/buildcache/ProjectInputCalculator.java @@ -26,5 +26,5 @@ */ public interface ProjectInputCalculator { - ProjectsInputInfo calculateInput(MavenProject project); + ProjectsInputInfo calculateInput(MavenProject project, Zone inputZone); } diff --git a/src/main/java/org/apache/maven/buildcache/RemoteCacheRepository.java b/src/main/java/org/apache/maven/buildcache/RemoteCacheRepository.java index b2fafc50..1c8bdf8b 100644 --- a/src/main/java/org/apache/maven/buildcache/RemoteCacheRepository.java +++ b/src/main/java/org/apache/maven/buildcache/RemoteCacheRepository.java @@ -41,11 +41,11 @@ public interface RemoteCacheRepository extends CacheRepository { * Returns true if success, false if the artifact does not exists * and throws an IOException if a problem occurs. */ - boolean getArtifactContent(CacheContext context, Artifact artifact, Path target) throws IOException; + boolean getArtifactContent(CacheContext context, Zone zone, Artifact artifact, Path target) throws IOException; @Nonnull - String getResourceUrl(CacheContext context, String filename); + String getResourceUrl(CacheContext context, Zone zone, String filename); @Nonnull - Optional findBaselineBuild(MavenProject project); + Optional findBaselineBuild(MavenProject project, Zone zone); } diff --git a/src/main/java/org/apache/maven/buildcache/RemoteCacheRepositoryImpl.java b/src/main/java/org/apache/maven/buildcache/RemoteCacheRepositoryImpl.java index 8d884cd7..6896d974 100644 --- a/src/main/java/org/apache/maven/buildcache/RemoteCacheRepositoryImpl.java +++ b/src/main/java/org/apache/maven/buildcache/RemoteCacheRepositoryImpl.java @@ -107,20 +107,20 @@ public void close() throws IOException { @Nonnull @Override - public Optional findBuild(CacheContext context) throws IOException { - final String resourceUrl = getResourceUrl(context, BUILDINFO_XML); + public Optional findBuild(CacheContext context, Zone inputZone) throws IOException { + final String resourceUrl = getResourceUrl(context, inputZone, BUILDINFO_XML); return getResourceContent(resourceUrl) .map(content -> new Build(xmlService.loadBuild(content), CacheSource.REMOTE)); } @Override - public boolean getArtifactContent(CacheContext context, Artifact artifact, Path target) { - return getResourceContent(getResourceUrl(context, artifact.getFileName()), target); + public boolean getArtifactContent(CacheContext context, Zone zone, Artifact artifact, Path target) { + return getResourceContent(getResourceUrl(context, zone, artifact.getFileName()), target); } @Override - public void saveBuildInfo(CacheResult cacheResult, Build build) throws IOException { - final String resourceUrl = getResourceUrl(cacheResult.getContext(), BUILDINFO_XML); + public void saveBuildInfo(CacheResult cacheResult, Zone outputZone, Build build) throws IOException { + final String resourceUrl = getResourceUrl(cacheResult.getContext(), outputZone, BUILDINFO_XML); putToRemoteCache(xmlService.toBytes(build.getDto()), resourceUrl); } @@ -136,9 +136,10 @@ public void saveCacheReport(String buildId, MavenSession session, CacheReport ca } @Override - public void saveArtifactFile(CacheResult cacheResult, org.apache.maven.artifact.Artifact artifact) + public void saveArtifactFile(CacheResult cacheResult, Zone outputZone, org.apache.maven.artifact.Artifact artifact) throws IOException { - final String resourceUrl = getResourceUrl(cacheResult.getContext(), CacheUtils.normalizedName(artifact)); + final String resourceUrl = + getResourceUrl(cacheResult.getContext(), outputZone, CacheUtils.normalizedName(artifact)); putToRemoteCache(artifact.getFile(), resourceUrl); } @@ -215,17 +216,18 @@ public boolean getResourceContent(String url, Path target) { @Nonnull @Override - public String getResourceUrl(CacheContext context, String filename) { + public String getResourceUrl(CacheContext context, Zone zone, String filename) { return getResourceUrl( filename, context.getProject().getGroupId(), context.getProject().getArtifactId(), - context.getInputInfo().getChecksum()); + context.getInputInfo().getChecksum(), + zone); } - private String getResourceUrl(String filename, String groupId, String artifactId, String checksum) { + private String getResourceUrl(String filename, String groupId, String artifactId, String checksum, Zone zone) { return MavenProjectInput.CACHE_IMPLEMENTATION_VERSION + "/" + groupId + "/" + artifactId + "/" + checksum + "/" - + filename; + + zone + "/" + filename; } private void putToRemoteCache(byte[] bytes, String url) throws IOException { @@ -258,7 +260,7 @@ private void putToRemoteCache(File file, String url) throws IOException { @Nonnull @Override - public Optional findBaselineBuild(MavenProject project) { + public Optional findBaselineBuild(MavenProject project, Zone zone) { Optional> cachedProjectsHolder = findCacheInfo().map(CacheReport::getProjects); if (!cachedProjectsHolder.isPresent()) { @@ -283,7 +285,7 @@ public Optional findBaselineBuild(MavenProject project) { LOGGER.info("Retrieving baseline buildinfo: {}", url); } else { url = getResourceUrl( - BUILDINFO_XML, project.getGroupId(), project.getArtifactId(), projectReport.getChecksum()); + BUILDINFO_XML, project.getGroupId(), project.getArtifactId(), projectReport.getChecksum(), zone); LOGGER.info("Baseline project record doesn't have url, trying default location {}", url); } diff --git a/src/main/java/org/apache/maven/buildcache/RemoteCacheRepositoryNoOp.java b/src/main/java/org/apache/maven/buildcache/RemoteCacheRepositoryNoOp.java index e66d0e52..2a405416 100644 --- a/src/main/java/org/apache/maven/buildcache/RemoteCacheRepositoryNoOp.java +++ b/src/main/java/org/apache/maven/buildcache/RemoteCacheRepositoryNoOp.java @@ -38,34 +38,34 @@ public class RemoteCacheRepositoryNoOp implements RemoteCacheRepository { @Nonnull @Override - public Optional findBuild(CacheContext context) throws IOException { + public Optional findBuild(CacheContext context, Zone inputZone) throws IOException { return Optional.empty(); } @Override - public void saveBuildInfo(CacheResult cacheResult, Build build) throws IOException {} + public void saveBuildInfo(CacheResult cacheResult, Zone outputZone, Build build) throws IOException {} @Override - public void saveArtifactFile(CacheResult cacheResult, Artifact artifact) throws IOException {} + public void saveArtifactFile(CacheResult cacheResult, Zone outputZone, Artifact artifact) throws IOException {} @Override public void saveCacheReport(String buildId, MavenSession session, CacheReport cacheReport) throws IOException {} @Override public boolean getArtifactContent( - CacheContext context, org.apache.maven.buildcache.xml.build.Artifact artifact, Path target) + CacheContext context, Zone zone, org.apache.maven.buildcache.xml.build.Artifact artifact, Path target) throws IOException { return false; } @Override - public String getResourceUrl(CacheContext context, String filename) { + public String getResourceUrl(CacheContext context, Zone zone, String filename) { return null; } @Nonnull @Override - public Optional findBaselineBuild(MavenProject project) { + public Optional findBaselineBuild(MavenProject project, Zone zone) { return Optional.empty(); } } diff --git a/src/main/java/org/apache/maven/buildcache/Zone.java b/src/main/java/org/apache/maven/buildcache/Zone.java new file mode 100644 index 00000000..7c4ac60d --- /dev/null +++ b/src/main/java/org/apache/maven/buildcache/Zone.java @@ -0,0 +1,65 @@ +/* + * 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.apache.maven.buildcache; + +import org.apache.commons.lang3.StringUtils; + +import static java.util.Objects.requireNonNull; + +/** + * @author Réda Housni Alaoui + */ +public class Zone { + + private final String name; + + public Zone(String name) { + if (StringUtils.isBlank(name)) { + throw new IllegalArgumentException("Zone name cannot be blank"); + } + this.name = requireNonNull(name); + } + + public String value() { + return name; + } + + @Override + public String toString() { + return name; + } + + @Override + public final boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Zone)) { + return false; + } + + Zone zone = (Zone) o; + return name.equals(zone.name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } +} diff --git a/src/main/java/org/apache/maven/buildcache/checksum/MavenProjectInput.java b/src/main/java/org/apache/maven/buildcache/checksum/MavenProjectInput.java index bd2a7287..5988059b 100644 --- a/src/main/java/org/apache/maven/buildcache/checksum/MavenProjectInput.java +++ b/src/main/java/org/apache/maven/buildcache/checksum/MavenProjectInput.java @@ -65,6 +65,7 @@ import org.apache.maven.buildcache.RemoteCacheRepository; import org.apache.maven.buildcache.ScanConfigProperties; import org.apache.maven.buildcache.Xpp3DomUtils; +import org.apache.maven.buildcache.Zone; import org.apache.maven.buildcache.checksum.exclude.ExclusionResolver; import org.apache.maven.buildcache.hash.HashAlgorithm; import org.apache.maven.buildcache.hash.HashChecksum; @@ -113,7 +114,7 @@ public class MavenProjectInput { /** * Version of cache implementation. It is recommended to change to simplify remote cache maintenance */ - public static final String CACHE_IMPLEMENTATION_VERSION = "v1.1"; + public static final String CACHE_IMPLEMENTATION_VERSION = "v1.2"; /** * property name to pass glob value. The glob to be used to list directory files in plugins scanning @@ -185,13 +186,13 @@ public MavenProjectInput( this.artifactHandlerManager = artifactHandlerManager; } - public ProjectsInputInfo calculateChecksum() throws IOException { + public ProjectsInputInfo calculateChecksum(Zone zone) throws IOException { final long t0 = System.currentTimeMillis(); final String effectivePom = getEffectivePom(normalizedModelProvider.normalizedModel(project)); final SortedSet inputFiles = isPom(project) ? Collections.emptySortedSet() : getInputFiles(); - final SortedMap dependenciesChecksum = getMutableDependencies(); - final SortedMap pluginDependenciesChecksum = getMutablePluginDependencies(); + final SortedMap dependenciesChecksum = getMutableDependencies(zone); + final SortedMap pluginDependenciesChecksum = getMutablePluginDependencies(zone); final long t1 = System.currentTimeMillis(); @@ -207,8 +208,8 @@ public ProjectsInputInfo calculateChecksum() throws IOException { Optional baselineHolder = Optional.empty(); if (config.isBaselineDiffEnabled()) { - baselineHolder = - remoteCache.findBaselineBuild(project).map(b -> b.getDto().getProjectsInputInfo()); + baselineHolder = remoteCache.findBaselineBuild(project, zone).map(b -> b.getDto() + .getProjectsInputInfo()); } if (config.calculateProjectVersionChecksum()) { @@ -638,11 +639,11 @@ private static boolean isReadable(Path entry) throws IOException { return Files.isReadable(entry); } - private SortedMap getMutableDependencies() throws IOException { - return getMutableDependenciesHashes("", project.getDependencies()); + private SortedMap getMutableDependencies(Zone zone) throws IOException { + return getMutableDependenciesHashes("", project.getDependencies(), zone); } - private SortedMap getMutablePluginDependencies() throws IOException { + private SortedMap getMutablePluginDependencies(Zone zone) throws IOException { Map keyPrefixOccurrenceIndex = new HashMap<>(); SortedMap fullMap = new TreeMap<>(); for (Plugin plugin : project.getBuildPlugins()) { @@ -654,8 +655,8 @@ private SortedMap getMutablePluginDependencies() throws IOExcept int occurrenceIndex = keyPrefixOccurrenceIndex .computeIfAbsent(rawKeyPrefix, k -> new AtomicInteger()) .getAndIncrement(); - fullMap.putAll( - getMutableDependenciesHashes(rawKeyPrefix + "|" + occurrenceIndex + "|", plugin.getDependencies())); + fullMap.putAll(getMutableDependenciesHashes( + rawKeyPrefix + "|" + occurrenceIndex + "|", plugin.getDependencies(), zone)); } return fullMap; } @@ -764,8 +765,8 @@ public Artifact createDependencyArtifact(Dependency d) { return artifact; } - private SortedMap getMutableDependenciesHashes(String keyPrefix, List dependencies) - throws IOException { + private SortedMap getMutableDependenciesHashes( + String keyPrefix, List dependencies, Zone zone) throws IOException { SortedMap result = new TreeMap<>(); for (Dependency dependency : dependencies) { @@ -790,8 +791,9 @@ private SortedMap getMutableDependenciesHashes(String keyPrefix, String projectHash; if (dependencyProject != null) // part of multi module { - projectHash = - projectInputCalculator.calculateInput(dependencyProject).getChecksum(); + projectHash = projectInputCalculator + .calculateInput(dependencyProject, zone) + .getChecksum(); } else // this is a snapshot dependency { DigestItem resolved = null; diff --git a/src/main/java/org/apache/maven/buildcache/xml/CacheConfig.java b/src/main/java/org/apache/maven/buildcache/xml/CacheConfig.java index d86b15d4..ec53677d 100644 --- a/src/main/java/org/apache/maven/buildcache/xml/CacheConfig.java +++ b/src/main/java/org/apache/maven/buildcache/xml/CacheConfig.java @@ -25,6 +25,7 @@ import java.util.regex.Pattern; import org.apache.maven.buildcache.PluginScanConfig; +import org.apache.maven.buildcache.Zone; import org.apache.maven.buildcache.hash.HashFactory; import org.apache.maven.buildcache.xml.config.DirName; import org.apache.maven.buildcache.xml.config.Exclude; @@ -152,4 +153,8 @@ public interface CacheConfig { * Flag to save in cache only if a build went through the clean lifecycle */ boolean isMandatoryClean(); + + List getInputZones(); + + List getOutputZones(); } diff --git a/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java b/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java index 566a067a..d6f8ee67 100644 --- a/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java +++ b/src/main/java/org/apache/maven/buildcache/xml/CacheConfigImpl.java @@ -31,12 +31,15 @@ import java.util.List; import java.util.Optional; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.apache.maven.SessionScoped; import org.apache.maven.buildcache.DefaultPluginScanConfig; import org.apache.maven.buildcache.PluginScanConfig; import org.apache.maven.buildcache.PluginScanConfigImpl; +import org.apache.maven.buildcache.Zone; import org.apache.maven.buildcache.hash.HashFactory; import org.apache.maven.buildcache.xml.config.AttachedOutputs; import org.apache.maven.buildcache.xml.config.CacheConfig; @@ -95,6 +98,8 @@ public class CacheConfigImpl implements org.apache.maven.buildcache.xml.CacheCon public static final String RESTORE_GENERATED_SOURCES_PROPERTY_NAME = "maven.build.cache.restoreGeneratedSources"; public static final String ALWAYS_RUN_PLUGINS = "maven.build.cache.alwaysRunPlugins"; public static final String MANDATORY_CLEAN = "maven.build.cache.mandatoryClean"; + public static final String INPUT_ZONES = "maven.build.cache.inputZones"; + public static final String OUTPUT_ZONES = "maven.build.cache.outputZones"; /** * Flag to control if we should skip lookup for cached artifacts globally or for a particular project even if @@ -111,6 +116,8 @@ public class CacheConfigImpl implements org.apache.maven.buildcache.xml.CacheCon */ public static final String SKIP_SAVE = "maven.build.cache.skipSave"; + private static final String DEFAULT_CACHE_ZONE = "default-zone"; + private static final Logger LOGGER = LoggerFactory.getLogger(CacheConfigImpl.class); private final XmlService xmlService; @@ -538,6 +545,30 @@ public boolean isMandatoryClean() { return getProperty(MANDATORY_CLEAN, getConfiguration().isMandatoryClean()); } + @Override + public List getInputZones() { + String rawCacheZones = getProperty(INPUT_ZONES, null); + if (StringUtils.isBlank(rawCacheZones)) { + return Collections.singletonList(new Zone(DEFAULT_CACHE_ZONE)); + } + return Stream.of(StringUtils.split(rawCacheZones, ",")) + .distinct() + .map(Zone::new) + .collect(Collectors.toList()); + } + + @Override + public List getOutputZones() { + String rawCacheZones = getProperty(OUTPUT_ZONES, null); + if (StringUtils.isBlank(rawCacheZones)) { + return Collections.singletonList(new Zone(DEFAULT_CACHE_ZONE)); + } + return Stream.of(StringUtils.split(rawCacheZones, ",")) + .distinct() + .map(Zone::new) + .collect(Collectors.toList()); + } + @Override public String getId() { checkInitializedState(); diff --git a/src/test/java/org/apache/maven/buildcache/its/AsymetricZonesTest.java b/src/test/java/org/apache/maven/buildcache/its/AsymetricZonesTest.java new file mode 100644 index 00000000..54414bc9 --- /dev/null +++ b/src/test/java/org/apache/maven/buildcache/its/AsymetricZonesTest.java @@ -0,0 +1,74 @@ +/* + * 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.apache.maven.buildcache.its; + +import org.apache.maven.buildcache.its.junit.IntegrationTest; +import org.apache.maven.it.VerificationException; +import org.apache.maven.it.Verifier; +import org.junit.jupiter.api.Test; + +import static org.apache.maven.buildcache.xml.CacheConfigImpl.INPUT_ZONES; +import static org.apache.maven.buildcache.xml.CacheConfigImpl.OUTPUT_ZONES; + +/** + * @author Réda Housni Alaoui + */ +@IntegrationTest("src/test/projects/asymetric-zones") +class AsymetricZonesTest { + + private static final String PROJECT_NAME = "org.apache.maven.caching.test.simple:simple"; + private static final String ZONE_1 = "zone1"; + private static final String ZONE_2 = "zone2"; + + @Test + void simple(Verifier verifier) throws VerificationException { + verifier.setAutoclean(false); + + verifier.getCliOptions().clear(); + verifier.addCliOption("-D" + INPUT_ZONES + "=" + ZONE_1); + verifier.addCliOption("-D" + OUTPUT_ZONES + "=" + ZONE_1); + verifier.setLogFileName("../log-1.txt"); + verifier.executeGoal("test"); + verifier.verifyErrorFreeLog(); + + verifier.getCliOptions().clear(); + verifier.addCliOption("-D" + INPUT_ZONES + "=" + ZONE_2 + "," + ZONE_1); + verifier.addCliOption("-D" + OUTPUT_ZONES + "=" + ZONE_2); + verifier.setLogFileName("../log-2.txt"); + verifier.executeGoal("verify"); + verifier.verifyErrorFreeLog(); + verifier.verifyTextInLog("Found cached build, restoring " + PROJECT_NAME + " from cache zone " + ZONE_1); + + verifier.getCliOptions().clear(); + verifier.addCliOption("-D" + INPUT_ZONES + "=" + ZONE_2 + "," + ZONE_1); + verifier.addCliOption("-D" + OUTPUT_ZONES + "=" + ZONE_2); + verifier.setLogFileName("../log-3.txt"); + verifier.executeGoal("verify"); + verifier.verifyErrorFreeLog(); + verifier.verifyTextInLog("Found cached build, restoring " + PROJECT_NAME + " from cache zone " + ZONE_2); + + verifier.getCliOptions().clear(); + verifier.addCliOption("-D" + INPUT_ZONES + "=" + ZONE_2); + verifier.addCliOption("-D" + OUTPUT_ZONES + "=" + ZONE_2); + verifier.setLogFileName("../log-4.txt"); + verifier.executeGoal("verify"); + verifier.verifyErrorFreeLog(); + verifier.verifyTextInLog("Found cached build, restoring " + PROJECT_NAME + " from cache zone " + ZONE_2); + } +} diff --git a/src/test/java/org/apache/maven/buildcache/its/IncrementalRestoreTest.java b/src/test/java/org/apache/maven/buildcache/its/IncrementalRestoreTest.java index 5656fc04..e0b9057f 100644 --- a/src/test/java/org/apache/maven/buildcache/its/IncrementalRestoreTest.java +++ b/src/test/java/org/apache/maven/buildcache/its/IncrementalRestoreTest.java @@ -84,7 +84,7 @@ public class IncrementalRestoreTest { public static final String JAR_DEFAULT_JAR_MBUILDCACHE_INCREMENTAL = "jar (default-jar) @ mbuildcache-incremental"; public static final String FOUND_CACHED_BUILD_RESTORING_ORG_APACHE_MAVEN_CACHING_TEST_MBUILDCACHE_INCREMENTAL_FROM_CACHE_BY_CHECKSUM = - "Found cached build, restoring org.apache.maven.caching.test:mbuildcache-incremental from cache by checksum"; + "Found cached build, restoring org.apache.maven.caching.test:mbuildcache-incremental from cache"; public static final String MBUILDCACHE_INCREMENTAL_JAR = "mbuildcache-incremental.jar"; public static final String MBUILDCACHE_INCREMENTAL_SOURCES_JAR = "mbuildcache-incremental-sources.jar"; public static final String MBUILDCACHE_INCREMENTAL_JAVADOC_JAR = "mbuildcache-incremental-javadoc.jar"; @@ -144,7 +144,7 @@ void simple(Verifier verifier) throws VerificationException, IOException { verifier.verifyTextInLog( FOUND_CACHED_BUILD_RESTORING_ORG_APACHE_MAVEN_CACHING_TEST_MBUILDCACHE_INCREMENTAL_FROM_CACHE_BY_CHECKSUM); verifier.verifyTextInLog( - "Found cached build, restoring org.apache.maven.caching.test:mbuildcache-incremental from cache by checksum"); + "Found cached build, restoring org.apache.maven.caching.test:mbuildcache-incremental from cache"); verifier.verifyErrorFreeLog(); verifier.verifyTextInLog(SKIPPING_PLUGIN_EXECUTION_CACHED_RESOURCES_RESOURCES); verifier.verifyTextInLog(SKIPPING_PLUGIN_EXECUTION_CACHED_COMPILER_COMPILE); diff --git a/src/test/java/org/apache/maven/buildcache/its/Issue67Test.java b/src/test/java/org/apache/maven/buildcache/its/Issue67Test.java index 672622fc..96a107d1 100644 --- a/src/test/java/org/apache/maven/buildcache/its/Issue67Test.java +++ b/src/test/java/org/apache/maven/buildcache/its/Issue67Test.java @@ -71,7 +71,7 @@ void simple(Verifier verifier) throws VerificationException, IOException { verifier.executeGoal("verify"); verifier.verifyTextInLog( - "Found cached build, restoring org.apache.maven.caching.test.mbuildcache-67:mbuildcache-67 from cache by checksum"); + "Found cached build, restoring org.apache.maven.caching.test.mbuildcache-67:mbuildcache-67 from cache"); verifier.verifyTextInLog("Cannot restore project artifacts, continuing with non cached build"); verifier.verifyErrorFreeLog(); diff --git a/src/test/projects/asymetric-zones/.mvn/maven-build-cache-config.xml b/src/test/projects/asymetric-zones/.mvn/maven-build-cache-config.xml new file mode 100644 index 00000000..f23c4673 --- /dev/null +++ b/src/test/projects/asymetric-zones/.mvn/maven-build-cache-config.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/src/test/projects/asymetric-zones/pom.xml b/src/test/projects/asymetric-zones/pom.xml new file mode 100644 index 00000000..f5265b40 --- /dev/null +++ b/src/test/projects/asymetric-zones/pom.xml @@ -0,0 +1,42 @@ + + + + 4.0.0 + org.apache.maven.caching.test.simple + simple + 0.0.1-SNAPSHOT + jar + + + 1.8 + 1.8 + + + + + + org.apache.maven.extensions + maven-build-cache-extension + ${projectVersion} + + + + + diff --git a/src/test/projects/asymetric-zones/src/main/java/org/apache/maven/buildcache/Test.java b/src/test/projects/asymetric-zones/src/main/java/org/apache/maven/buildcache/Test.java new file mode 100644 index 00000000..03f66a82 --- /dev/null +++ b/src/test/projects/asymetric-zones/src/main/java/org/apache/maven/buildcache/Test.java @@ -0,0 +1,24 @@ +/* + * 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.apache.maven.buildcache; + +class Test +{ + +} \ No newline at end of file