All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.helidon.build.maven.cache.LifecycleManager Maven / Gradle / Ivy

/*
 * Copyright (c) 2024 Oracle and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.helidon.build.maven.cache;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.maven.SessionScoped;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.ExecutionListener;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.logging.Logger;

/**
 * Manages the "fast-forward" feature.
 */
@Named
@SessionScoped
public class LifecycleManager {

    @Inject
    private ProjectStateManager stateManager;

    @Inject
    private ProjectExecutionManager executionManager;

    @Inject
    private CacheConfigManager configManager;

    @Inject
    private MavenSession session;

    @Inject
    private Logger logger;

    private final CountDownLatch latch = new CountDownLatch(1);
    private final AtomicBoolean initialized = new AtomicBoolean(false);

    /**
     * Update the lifecycle to fast-forward cached executions.
     */
    public void afterProjectsRead() {
        MavenExecutionRequest request = session.getRequest();
        request.setExecutionListener(new ExecutionListenerImpl(request.getExecutionListener()));
    }

    private void initState(MavenSession session) {
        if (initialized.compareAndSet(false, true)) {
            if (session.getGoals().contains("clean")) {
                logger.debug("Clean requested, state is ignored");
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing state files...");
                }
                stateManager.states().forEach((p, stateStatus) -> {
                    if (stateStatus.code() != ProjectStateStatus.STATE_UNAVAILABLE) {
                        if (stateStatus.code() == ProjectStateStatus.STATE_VALID) {
                            if (logger.isDebugEnabled()) {
                                logger.debug(String.format("[%s:%s] - applying state",
                                        p.getGroupId(),
                                        p.getArtifactId()));
                            }
                            stateStatus.state().apply(p, session);
                        }
                        executionManager.processExecutions(p, stateStatus);
                    }
                });
                logger.info(String.format("Loaded %s state file(s)", stateManager.loaded()));
            }
            latch.countDown();
        } else {
            awaitInit();
        }
    }

    private void awaitInit() {
        try {
            latch.await();
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);
        }
    }

    private final class ExecutionListenerImpl extends DelegatingExecutionListener {

        ExecutionListenerImpl(ExecutionListener delegate) {
            super(delegate);
        }

        @Override
        public void projectStarted(ExecutionEvent event) {
            super.projectStarted(event);
            initState(event.getSession());
            MavenProject project = event.getProject();
            CacheConfig.LifecycleConfig lifeCycleConfig = configManager.lifecycleConfig(project);
            ProjectExecutionPlan plan = executionManager.plan(project);
            if (!lifeCycleConfig.enabled()) {
                logger.info("Cache is disabled");
            } else if (plan == null) {
                logger.info("State is not available");
            } else if (plan.hasInvalidDownstream()) {
                logger.info("Downstream state(s) not available, state is ignored");
            } else if (!plan.hasFileChanges() && plan.allCached()) {
                logger.info("All executions are cached! (fast-forward)");
            } else if (plan.hasFileChanges()) {
                logger.info("File changes detected, state is ignored");
                ProjectStateStatus stateStatus = plan.stateStatus();
                stateStatus.state()
                        .projectFiles()
                        .diff(stateStatus.projectFiles())
                        .forEach(diff -> logger.info("  +- " + diff.asString()));
            } else {
                plan.executionStatuses()
                        .stream()
                        .filter(s -> !s.isNew())
                        .forEach(s -> {
                            logger.info(s.toString());
                            if (s.isDiff()) {
                                List diffs = s.diffs();
                                for (ConfigDiff diff : diffs) {
                                    logger.info("           +- " + diff.asString());
                                }
                            }
                        });
            }
        }

        @Override
        public void mojoSucceeded(ExecutionEvent event) {
            super.mojoSucceeded(event);
            executionManager.recordExecution(event.getMojoExecution(), event.getProject());
        }

        @Override
        public void projectSucceeded(ExecutionEvent event) {
            super.projectSucceeded(event);
            MavenProject project = event.getProject();
            if (configManager.lifecycleConfig(project).enabled()) {
                stateManager.save(project);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy