/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.gradle.plugins.cache.task; import com.liferay.gradle.plugins.cache.CacheExtension; import com.liferay.gradle.plugins.cache.util.FileUtil; import com.liferay.gradle.plugins.cache.util.StringUtil; import com.liferay.gradle.util.GradleUtil; import com.liferay.gradle.util.Validator; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Set; import org.gradle.api.Action; import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.logging.Logger; import org.gradle.api.plugins.BasePlugin; import org.gradle.api.tasks.Copy; /** * @author Andrea Di Giorgi */ public class TaskCacheApplicator { public static final String DIGEST_FILE_NAME = ".digest"; public void apply(CacheExtension cacheExtension, TaskCache taskCache) { Task task = taskCache.getTask(); Logger logger = task.getLogger(); boolean upToDate = false; String currentDigest = getCurrentDigest(taskCache); if (logger.isInfoEnabled()) { logger.info("Current digest is " + currentDigest); } if (cacheExtension.isForcedCache()) { File cacheDir = taskCache.getCacheDir(); if (!cacheDir.exists()) { throw new GradleException("Unable to find " + cacheDir); } upToDate = true; } else if (taskCache.isDisabled()) { if (logger.isLifecycleEnabled()) { logger.lifecycle("Cache for " + task + " is disabled"); } } else { String cachedDigest = getCachedDigest(taskCache); if (logger.isInfoEnabled()) { if (Validator.isNull(cachedDigest)) { logger.info("No cached digest has been found"); } else { logger.info("Cached digest is " + cachedDigest); } } if (cachedDigest.equals(currentDigest)) { upToDate = true; } } if (upToDate) { applyUpToDate(taskCache, task); } else { applyOutOfDate(taskCache, task, currentDigest); } createRefreshDigestTask(taskCache); } protected void applyOutOfDate( final TaskCache taskCache, Task task, final String currentDigest) { Logger logger = task.getLogger(); if (logger.isInfoEnabled()) { logger.info(task + " is out-of-date"); } Copy copy = createSaveCacheTask(taskCache); copy.doLast( new Action<Task>() { @Override public void execute(Task task) { writeDigestFile(taskCache, currentDigest); } }); task.finalizedBy(copy); } protected void applyUpToDate(TaskCache taskCache, Task task) { Logger logger = task.getLogger(); if (logger.isInfoEnabled()) { logger.info(task + " is up-to-date"); } removeSkippedTaskDependencies(taskCache, task); Copy copy = createRestoreCacheTask(taskCache); task.dependsOn(copy); task.setEnabled(false); } protected Task createRefreshDigestTask(final TaskCache taskCache) { Project project = taskCache.getProject(); Task task = project.task(taskCache.getRefreshDigestTaskName()); task.doLast( new Action<Task>() { @Override public void execute(Task task) { String digest = getCurrentDigest(taskCache); writeDigestFile(taskCache, digest); } }); task.setDescription("Refresh the digest for " + taskCache); return task; } protected Copy createRestoreCacheTask(TaskCache taskCache) { Project project = taskCache.getProject(); Copy copy = GradleUtil.addTask( project, taskCache.getRestoreCacheTaskName(), Copy.class); copy.exclude(DIGEST_FILE_NAME); copy.from(taskCache.getCacheDir()); copy.into(taskCache.getBaseDir()); copy.setDescription( "Restores the cached output files of " + taskCache.getTask() + "."); return copy; } protected Copy createSaveCacheTask(TaskCache taskCache) { String taskName = taskCache.getSaveCacheTaskName(); Copy copy = GradleUtil.addTask( taskCache.getProject(), taskName, Copy.class); Task task = taskCache.getTask(); copy.dependsOn( task, BasePlugin.CLEAN_TASK_NAME + StringUtil.capitalize(taskName)); copy.from(taskCache.getFiles()); copy.into(taskCache.getCacheDir()); copy.setDescription("Caches the output files of " + task + "."); return copy; } protected String getCachedDigest(TaskCache taskCache) { try { File digestFile = new File( taskCache.getCacheDir(), DIGEST_FILE_NAME); if (!digestFile.exists()) { return ""; } return new String( Files.readAllBytes(digestFile.toPath()), StandardCharsets.UTF_8); } catch (IOException ioe) { throw new GradleException("Unable to read digest file", ioe); } } protected String getCurrentDigest(TaskCache taskCache) { return FileUtil.getDigest( taskCache.getProject(), taskCache.getTestFiles(), taskCache.isExcludeIgnoredTestFiles()); } protected void removeSkippedTaskDependencies( TaskCache taskCache, Task task) { Logger logger = task.getLogger(); Set<Object> taskDependencies = task.getDependsOn(); Set<Object> skippedTaskDependencies = taskCache.getSkippedTaskDependencies(); if (skippedTaskDependencies.isEmpty()) { taskDependencies.clear(); if (logger.isInfoEnabled()) { logger.info("Removed all dependencies from " + task); } } else { for (Object taskDependency : skippedTaskDependencies) { boolean removed = taskDependencies.remove(taskDependency); if (!removed && (taskDependency instanceof Task)) { Task taskDependencyTask = (Task)taskDependency; removed = taskDependencies.remove( taskDependencyTask.getName()); } if (removed) { if (logger.isInfoEnabled()) { logger.info( "Removed dependency " + taskDependency + " from " + task); } } else if (logger.isWarnEnabled()) { logger.warn( "Unable to remove skipped task dependency " + taskDependency); } } } } protected void writeDigestFile(TaskCache taskCache, String digest) { Task task = taskCache.getTask(); Logger logger = task.getLogger(); File digestFile = new File(taskCache.getCacheDir(), DIGEST_FILE_NAME); try { Files.write( digestFile.toPath(), digest.getBytes(StandardCharsets.UTF_8)); if (logger.isInfoEnabled()) { logger.info("Updated digest file to " + digest); } } catch (IOException ioe) { throw new GradleException("Unable to write digest file", ioe); } } }