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

org.apache.camel.maven.packaging.XRefCheckMojo Maven / Gradle / Ivy

The newest version!
/*
 * 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.camel.maven.packaging;

import java.io.IOError;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.camel.tooling.util.PackageHelper;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.snakeyaml.engine.v2.api.Load;
import org.snakeyaml.engine.v2.api.LoadSettings;

@Mojo(name = "xref-check", threadSafe = true)
public class XRefCheckMojo extends AbstractMojo {

    public static final java.lang.String PLAYBOOK = "antora-playbook-local-xref-check.yml";
    /**
     * The maven project.
     */
    @Parameter(property = "project", required = true, readonly = true)
    protected MavenProject project;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        try {
            List unresolved = checkXRef(project.getBasedir().toPath());
            if (!unresolved.isEmpty()) {
                getLog().error("Unresolved xrefs:");
                for (String ref : unresolved) {
                    getLog().error("  " + ref);
                }
                throw new MojoFailureException("Unresolved xrefs");
            }
        } catch (IOException e) {
            throw new MojoFailureException("Error checking xref", e);
        }
    }

    public List checkXRef(Path path) throws IOException {
        List unresolved = new ArrayList<>();
        Load yaml = new Load(LoadSettings.builder().build());
        Map site;
        try (Reader r = Files.newBufferedReader(path.resolve(PLAYBOOK))) {
            site = (Map) yaml.loadFromReader(r);
        }
        Map attributes = (Map) ((Map) site.get("asciidoc")).get("attributes");
        if (attributes != null) {
            attributes = attributes.entrySet().stream()
                    .collect(Collectors.toMap(e -> "{" + e.getKey() + "}", Map.Entry::getValue));
        }
        Map> componentPaths = new HashMap<>();
        Map> componentNavs = new HashMap<>();
        Map pages = new TreeMap<>();
        for (Map source : (List) ((Map) site.get("content")).get("sources")) {
            String url = (String) source.get("url");
            String startPath = (String) source.get("start_path");
            Path root = path.resolve(url).resolve(startPath).normalize();
            Map antora;
            try (Reader r = Files.newBufferedReader(root.resolve("antora.yml"))) {
                antora = (Map) yaml.loadFromReader(r);
            }
            String name = (String) antora.get("name");
            componentPaths.computeIfAbsent(name, n -> new ArrayList<>()).add(root);
            componentNavs.computeIfAbsent(name, n -> new ArrayList<>()).addAll(
                    Optional.ofNullable((List) antora.get("nav")).orElse(Collections.emptyList()));
        }
        for (Map.Entry> entry : componentPaths.entrySet()) {
            String component = entry.getKey();
            for (String nav : componentNavs.get(component)) {
                Optional n = entry.getValue().stream().map(p -> p.resolve(nav))
                        .filter(Files::isRegularFile)
                        .findFirst();
                if (n.isPresent()) {
                    Path f = n.get();
                    Path m = f.getParent();
                    while (!m.getParent().getFileName().toString().equals("modules")) {
                        m = m.getParent();
                    }
                    pages.put(component + ":" + m.getFileName().toString() + ":" + f.getFileName().toString(), n.get());
                }
            }
            for (Path root : entry.getValue()) {
                try (Stream stream = Files.list(root.resolve("modules"))) {
                    stream.filter(Files::isDirectory)
                            .filter(p -> Files.isDirectory(p.resolve("pages")))
                            .forEach(module -> {
                                String m = module.getFileName().toString();
                                Path pagesDir = module.resolve("pages");
                                try (Stream pageStream = walk(pagesDir)
                                        .filter(Files::isRegularFile)) {
                                    pageStream
                                            .forEach(page -> {
                                                Path rel = pagesDir.relativize(page);
                                                pages.put(component + ":" + m + ":" + rel, page);
                                            });
                                }
                            });
                }
            }
        }

        Pattern xref = Pattern.compile("\\b(?xref:(?[^\\[]+.adoc)[^\\]]*\\])");
        for (Map.Entry page : pages.entrySet()) {
            int firstDot = page.getKey().indexOf(':');
            int secondDot = firstDot >= 0 ? page.getKey().indexOf(':', firstDot + 1) : -1;
            String component = secondDot >= 0 ? page.getKey().substring(0, firstDot) : "";
            String module = secondDot >= 0 ? page.getKey().substring(firstDot + 1, secondDot) : "";
            String str = PackageHelper.loadText(page.getValue());
            for (Map.Entry repl : attributes.entrySet()) {
                str = str.replace(repl.getKey(), repl.getValue());
            }
            Matcher m = xref.matcher(str);
            while (m.find()) {
                String link = m.group("link");
                String all = m.group("all");
                String[] groups = link.split(":");
                String cl;
                String ml;
                String rem;
                if (groups.length == 3) {
                    cl = groups[0];
                    ml = groups[1].isEmpty() ? "ROOT" : groups[1];
                    rem = groups[2];
                } else if (groups.length == 2) {
                    cl = component;
                    ml = groups[0];
                    rem = groups[1];
                } else {
                    cl = component;
                    ml = module;
                    rem = groups[0];
                }
                if (cl.startsWith("latest@")) {
                    cl = cl.substring("latest@".length());
                }
                link = cl + ":" + ml + ":" + rem;
                if (!pages.containsKey(link)) {
                    long line = str.chars().limit(m.start()).filter(c -> c == '\n').count() + 1;
                    String prnt = Stream.of(all.split("\n")).map(String::trim).collect(Collectors.joining(" "));
                    unresolved.add(page.getKey() + " (" + page.getValue() + ") at line " + line + ": " + prnt);
                }
            }
        }

        return unresolved;
    }

    private Stream walk(Path p) {
        try {
            return Files.walk(p);
        } catch (IOException e) {
            throw new IOError(e);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy