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

org.gradle.internal.filewatch.jdk7.WatchPointsRegistry Maven / Gradle / Ivy

There is a newer version: 8.6
Show newest version
/*
 * Copyright 2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.gradle.internal.filewatch.jdk7;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.gradle.api.internal.file.FileSystemSubset;
import org.gradle.api.internal.file.ImmutableDirectoryTree;
import org.gradle.internal.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

class WatchPointsRegistry {
    private final static Logger LOG = LoggerFactory.getLogger(WatchPointsRegistry.class);
    private final CombinedRootSubset rootSubset = new CombinedRootSubset();
    private ImmutableSet allRequestedRoots;
    private final boolean createNewStartingPointsUnderExistingRoots;

    public WatchPointsRegistry(boolean createNewStartingPointsUnderExistingRoots) {
        this.createNewStartingPointsUnderExistingRoots = createNewStartingPointsUnderExistingRoots;
        allRequestedRoots = ImmutableSet.of();
    }

    public Delta appendFileSystemSubset(FileSystemSubset fileSystemSubset, Iterable currentWatchPoints) {
        return new Delta(fileSystemSubset, ImmutableSet.copyOf(currentWatchPoints));
    }

    public boolean shouldFire(File file) {
        return rootSubset.contains(file);
    }

    public boolean shouldWatch(File directory) {
        final boolean result = rootSubset.isInRootsOrAncestorOrAnyRoot(directory) || isAncestorOfAnyRoot(directory, allRequestedRoots, true);
        if (!result && LOG.isDebugEnabled()) {
            LOG.debug("not watching directory: {} allRequestedRoots: {} roots: {} unfiltered: {}", directory, allRequestedRoots, rootSubset.roots, rootSubset.combinedFileSystemSubset);
        }
        return result;
    }

    class Delta {
        private FileSystemSubset fileSystemSubset;
        private Iterable roots;
        private FileSystemSubset combinedRoots;
        private Iterable startingWatchPoints;
        private ImmutableSet currentWatchPoints;

        private Delta(FileSystemSubset fileSystemSubset, ImmutableSet currentWatchPoints) {
            this.fileSystemSubset = fileSystemSubset;
            this.currentWatchPoints = currentWatchPoints;
            init();
        }

        private Delta init() {
            roots = fileSystemSubset.getRoots();
            combinedRoots = fileSystemSubset.unfiltered();
            Iterable startingWatchPointCandidates = calculateStartingWatchPoints(roots, combinedRoots);
            if (!currentWatchPoints.isEmpty()) {
                if (createNewStartingPointsUnderExistingRoots) {
                    startingWatchPoints = filterCurrentWatchPoints(startingWatchPointCandidates);
                    currentWatchPoints = ImmutableSet.builder().addAll(currentWatchPoints).addAll(startingWatchPoints).build();
                } else {
                    Iterable combinedRoots = FileUtils.calculateRoots(Iterables.concat(currentWatchPoints, startingWatchPointCandidates));
                    startingWatchPoints = filterCurrentWatchPoints(combinedRoots);
                    currentWatchPoints = ImmutableSet.copyOf(combinedRoots);
                }
                rootSubset.append(fileSystemSubset);
            } else {
                startingWatchPoints = startingWatchPointCandidates;
                rootSubset.append(fileSystemSubset);
                currentWatchPoints = ImmutableSet.copyOf(startingWatchPoints);
            }
            allRequestedRoots = ImmutableSet.builder().addAll(allRequestedRoots).addAll(roots).build();
            return this;
        }

        private ImmutableSet filterCurrentWatchPoints(Iterable startingWatchPointCandidates) {
            final ImmutableSet.Builder newStartingPoints = ImmutableSet.builder();
            for (File file : startingWatchPointCandidates) {
                if (!allRequestedRoots.contains(file) || !currentWatchPoints.contains(file)) {
                    newStartingPoints.add(file);
                }
            }
            return newStartingPoints.build();
        }

        private Iterable calculateStartingWatchPoints(final Iterable roots, final FileSystemSubset unfiltered) {
            // Turn the requested watch points into actual enclosing directories that exist
            Iterable enclosingDirsThatExist = Iterables.transform(roots, new Function() {
                @Override
                public File apply(File input) {
                    File target = input;
                    while (!target.isDirectory()) {
                        target = target.getParentFile();
                    }
                    return target;
                }
            });

            // Collapse the set
            return Iterables.filter(FileUtils.calculateRoots(enclosingDirsThatExist), new Predicate() {
                @Override
                public boolean apply(File input) {
                    return inCombinedRootsOrAncestorOfAnyRoot(input, roots, unfiltered);
                }
            });
        }

        private boolean inCombinedRootsOrAncestorOfAnyRootThis(File file) {
            return inCombinedRootsOrAncestorOfAnyRoot(file, roots, combinedRoots);
        }

        public Iterable getStartingWatchPoints() {
            return startingWatchPoints;
        }

        public boolean shouldWatch(File file) {
            boolean result = inCombinedRootsOrAncestorOfAnyRootThis(file) || isAncestorOfAnyRoot(file, allRequestedRoots);
            if (!result) {
                LOG.debug("not watching file: {} currentWatchPoints: {} allRequestedRoots: {} roots: {} unfiltered: {}", file, currentWatchPoints, allRequestedRoots, roots, combinedRoots);
            }
            return result;
        }
    }

    static private boolean inCombinedRootsOrAncestorOfAnyRoot(File file, Iterable roots, FileSystemSubset combinedRootsSubset) {
        return combinedRootsSubset.contains(file) || isAncestorOfAnyRoot(file, roots, true);
    }

    static private boolean isAncestorOfAnyRoot(File file, Iterable roots) {
        return isAncestorOfAnyRoot(file, roots, false);
    }

    static private boolean isAncestorOfAnyRoot(File file, Iterable roots, boolean acceptItSelf) {
        String absolutePathWithSeparator = file.getAbsolutePath() + File.separator;
        for (File root : roots) {
            if ((acceptItSelf && root.equals(file)) || root.getAbsolutePath().startsWith(absolutePathWithSeparator)) {
                return true;
            }
        }
        return false;
    }

    private static class CombinedRootSubset {
        private final FileSystemSubset.Builder combinedFileSystemSubsetBuilder;

        private Iterable roots;
        private FileSystemSubset unfiltered;
        private FileSystemSubset combinedFileSystemSubset;

        public CombinedRootSubset() {
            combinedFileSystemSubsetBuilder = FileSystemSubset.builder();
        }

        public void append(FileSystemSubset fileSystemSubset) {
            combinedFileSystemSubsetBuilder.add(fileSystemSubset);
            roots = null;
        }

        private void ensureRootsUpToDate() {
            if (roots != null) {
                return;
            }
            combinedFileSystemSubset = combinedFileSystemSubsetBuilder.build();
            roots = combinedFileSystemSubset.getRoots();
            unfiltered = new FileSystemSubset(ImmutableList.copyOf(roots), ImmutableList.of());
        }

        public boolean isInRootsOrAncestorOrAnyRoot(File directory) {
            ensureRootsUpToDate();
            return inCombinedRootsOrAncestorOfAnyRoot(directory, roots, unfiltered);
        }

        public boolean contains(File file) {
            ensureRootsUpToDate();
            return combinedFileSystemSubset.contains(file);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy