<commit_before>package org.bndtools.builder;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;

import aQute.bnd.build.Project;
import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.Instructions;
import aQute.bnd.osgi.Processor;
import aQute.lib.io.IO;
import bndtools.central.Central;

class DeltaWrapper {

    private static final Path EXT = new Path("/cnf/ext");
    private final Project model;
    private final IResourceDelta delta;
    private final BuildLogger log;

    DeltaWrapper(Project model, IResourceDelta delta, BuildLogger log) {
        this.model = model;
        this.delta = delta;
        this.log = log;
    }

    boolean hasCnfChanged() throws Exception {
        if (delta == null) {
            log.basic("Full build because delta for cnf is null");
            return true;
        }

        if (havePropertiesChanged(model.getWorkspace())) {
            log.basic("cnf properties have changed");
            return true;
        }

        if (isNonMarkerChange(delta.findMember(EXT)))
            return true;

        return false;
    }

    boolean isNonMarkerChange(IResourceDelta delta) {
        if (delta == null)
            return false;
        int kindMask = IResourceDelta.CHANGED | IResourceDelta.ADDED | IResourceDelta.REMOVED;
        if ((kindMask & delta.getKind()) > 0) {
            int flags = delta.getFlags();
            if (flags > 0 && flags != IResourceDelta.MARKERS) {
                log.basic("Delta affects resource %s with kind=%d and flags=%d", delta.getFullPath(), delta.getKind(), delta.getFlags());
                return true;
            }
        }

        IResourceDelta[] children = delta.getAffectedChildren();
        if (children != null)
            for (IResourceDelta child : children) {
                if (isNonMarkerChange(child))
                    return true;
            }

        return false;
    }

    /*
     * Any change other then src, test, test_bin, or generated is fair game.
     */
    boolean hasProjectChanged() throws Exception {

        if (delta == null) {
            log.basic("Full build because delta is null");
            return true;
        }

        final AtomicBoolean result = new AtomicBoolean(false);
        delta.accept(new IResourceDeltaVisitor() {

            @Override
            public boolean visit(IResourceDelta visitDelta) throws CoreException {

                if ((delta.getKind() & (IResourceDelta.ADDED | IResourceDelta.CHANGED | IResourceDelta.REMOVED)) == 0)
                    return false;

                IResource resource = visitDelta.getResource();
                if (resource.getType() == IResource.ROOT || resource.getType() == IResource.PROJECT)
                    return true;

                String path = resource.getProjectRelativePath().toString();

                if (resource.getType() == IResource.FOLDER) {
                    if (check(path, model.getProperty(Constants.DEFAULT_PROP_SRC_DIR)) //
                            || check(path, model.getProperty(Constants.DEFAULT_PROP_TESTSRC_DIR)) //
                            || check(path, model.getProperty(Constants.DEFAULT_PROP_TESTBIN_DIR)) //
                            || check(path, model.getProperty(Constants.DEFAULT_PROP_TARGET_DIR))) {
                        return false;

                    }

                }

                if (IResourceDelta.MARKERS == delta.getFlags())
                    return false;

                if (check(path, Project.BNDFILE))
                    return false;

                log.basic("%s changed", resource);
                result.set(true);
                return false;
            }

        });

        return result.get();
    }

    boolean hasBuildfile() throws Exception {
        File f = new File(model.getTarget(), Project.BUILDFILES);
        return has(f);
    }

    boolean havePropertiesChanged(Processor processor) throws Exception {

        if (has(processor.getPropertiesFile()))
            return true;

        List<File> included = processor.getIncluded();
        if (included == null)
            return false;

        for (File incl : included) {
            if (has(incl))
                return true;
        }

        return false;
    }

    private boolean has(File f) throws Exception {

        if (f == null)
            return false;

        if (delta == null)
            return false;

        IPath path = Central.toPath(f);
        if (path == null)
            return false;

        IPath relativePath = path.makeRelativeTo(delta.getFullPath());
        if (relativePath == null)
            return false;

        IResourceDelta delta = this.delta.findMember(relativePath);
        if (delta == null)
            return false;

        //
        // If ONLY the markers are changed we should ignore this delta
        // or get an infinite loop
        //

        if ((delta.getFlags() == IResourceDelta.MARKERS))
            return false;

        if (delta.getKind() == IResourceDelta.ADDED || delta.getKind() == IResourceDelta.CHANGED || delta.getKind() == IResourceDelta.REMOVED)
            return true;

        return false;
    }

    static boolean check(String changed, String prefix) {
        if (changed.equals(prefix))
            return true;

        if (changed.length() <= prefix.length())
            return false;

        char c = changed.charAt(prefix.length());
        if (c == '/' && changed.startsWith(prefix))
            return true;

        return false;
    }

    public boolean isTestBin(IResource resource) {
        String path = resource.getProjectRelativePath().toString();
        return check(path, model.getProperty(Constants.DEFAULT_PROP_TESTSRC_DIR));
    }

    /**
     * Check if the target JARs have gone. We look for the buildfiles and the listed jars. If anything is odd, we
     * rebuild.
     */
    public boolean hasNoTarget(Project model) throws Exception {

        //
        // $/buildfiles must exists
        //

        File[] buildFiles = model.getBuildFiles(false);
        if (buildFiles == null)
            return true;

        File file = IO.getFile(model.getTarget(), Project.BUILDFILES);
        if (!file.isFile())
            return true;

        //
        // buildfiles = line +
        //
<commit_msg>builder: Processor.getInclude can no longer return null<commit_after>package org.bndtools.builder;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;

import aQute.bnd.build.Project;
import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.Instructions;
import aQute.bnd.osgi.Processor;
import aQute.lib.io.IO;
import bndtools.central.Central;

class DeltaWrapper {

    private static final Path EXT = new Path("/cnf/ext");
    private final Project model;
    private final IResourceDelta delta;
    private final BuildLogger log;

    DeltaWrapper(Project model, IResourceDelta delta, BuildLogger log) {
        this.model = model;
        this.delta = delta;
        this.log = log;
    }

    boolean hasCnfChanged() throws Exception {
        if (delta == null) {
            log.basic("Full build because delta for cnf is null");
            return true;
        }

        if (havePropertiesChanged(model.getWorkspace())) {
            log.basic("cnf properties have changed");
            return true;
        }

        if (isNonMarkerChange(delta.findMember(EXT)))
            return true;

        return false;
    }

    boolean isNonMarkerChange(IResourceDelta delta) {
        if (delta == null)
            return false;
        int kindMask = IResourceDelta.CHANGED | IResourceDelta.ADDED | IResourceDelta.REMOVED;
        if ((kindMask & delta.getKind()) > 0) {
            int flags = delta.getFlags();
            if (flags > 0 && flags != IResourceDelta.MARKERS) {
                log.basic("Delta affects resource %s with kind=%d and flags=%d", delta.getFullPath(), delta.getKind(), delta.getFlags());
                return true;
            }
        }

        IResourceDelta[] children = delta.getAffectedChildren();
        if (children != null)
            for (IResourceDelta child : children) {
                if (isNonMarkerChange(child))
                    return true;
            }

        return false;
    }

    /*
     * Any change other then src, test, test_bin, or generated is fair game.
     */
    boolean hasProjectChanged() throws Exception {

        if (delta == null) {
            log.basic("Full build because delta is null");
            return true;
        }

        final AtomicBoolean result = new AtomicBoolean(false);
        delta.accept(new IResourceDeltaVisitor() {

            @Override
            public boolean visit(IResourceDelta visitDelta) throws CoreException {

                if ((delta.getKind() & (IResourceDelta.ADDED | IResourceDelta.CHANGED | IResourceDelta.REMOVED)) == 0)
                    return false;

                IResource resource = visitDelta.getResource();
                if (resource.getType() == IResource.ROOT || resource.getType() == IResource.PROJECT)
                    return true;

                String path = resource.getProjectRelativePath().toString();

                if (resource.getType() == IResource.FOLDER) {
                    if (check(path, model.getProperty(Constants.DEFAULT_PROP_SRC_DIR)) //
                            || check(path, model.getProperty(Constants.DEFAULT_PROP_TESTSRC_DIR)) //
                            || check(path, model.getProperty(Constants.DEFAULT_PROP_TESTBIN_DIR)) //
                            || check(path, model.getProperty(Constants.DEFAULT_PROP_TARGET_DIR))) {
                        return false;

                    }

                }

                if (IResourceDelta.MARKERS == delta.getFlags())
                    return false;

                if (check(path, Project.BNDFILE))
                    return false;

                log.basic("%s changed", resource);
                result.set(true);
                return false;
            }

        });

        return result.get();
    }

    boolean hasBuildfile() throws Exception {
        File f = new File(model.getTarget(), Project.BUILDFILES);
        return has(f);
    }

    boolean havePropertiesChanged(Processor processor) throws Exception {

        if (has(processor.getPropertiesFile()))
            return true;

        for (File incl : processor.getIncluded()) {
            if (has(incl))
                return true;
        }

        return false;
    }

    private boolean has(File f) throws Exception {

        if (f == null)
            return false;

        if (delta == null)
            return false;

        IPath path = Central.toPath(f);
        if (path == null)
            return false;

        IPath relativePath = path.makeRelativeTo(delta.getFullPath());
        if (relativePath == null)
            return false;

        IResourceDelta delta = this.delta.findMember(relativePath);
        if (delta == null)
            return false;

        //
        // If ONLY the markers are changed we should ignore this delta
        // or get an infinite loop
        //

        if ((delta.getFlags() == IResourceDelta.MARKERS))
            return false;

        if (delta.getKind() == IResourceDelta.ADDED || delta.getKind() == IResourceDelta.CHANGED || delta.getKind() == IResourceDelta.REMOVED)
            return true;

        return false;
    }

    static boolean check(String changed, String prefix) {
        if (changed.equals(prefix))
            return true;

        if (changed.length() <= prefix.length())
            return false;

        char c = changed.charAt(prefix.length());
        if (c == '/' && changed.startsWith(prefix))
            return true;

        return false;
    }

    public boolean isTestBin(IResource resource) {
        String path = resource.getProjectRelativePath().toString();
        return check(path, model.getProperty(Constants.DEFAULT_PROP_TESTSRC_DIR));
    }

    /**
     * Check if the target JARs have gone. We look for the buildfiles and the listed jars. If anything is odd, we rebuild.
     */
    public boolean hasNoTarget(Project model) throws Exception {

        //
        // $/buildfiles must exists
        //

        File[] buildFiles = model.getBuildFiles(false);
        if (buildFiles == null)
            return true;

        File file = IO.getFile(model.getTarget(), Project.BUILDFILES);
        if (!file.isFile())
            return true;

        //
        // buildfiles = line +
        //

{'fraction_non_alphanumeric': 0.10159542444310657, 'fraction_numerical': 0.0004515352197471403, 'mean_word_length': 1.9459099977831966, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3869712', 'n_tokens_mistral': 3556, 'n_tokens_neox': 3415, 'n_words': 882}