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

io.quarkus.devtools.codestarts.CodestartCatalogLoader Maven / Gradle / Ivy

There is a newer version: 3.17.0.CR1
Show newest version
package io.quarkus.devtools.codestarts;

import static io.quarkus.devtools.codestarts.Codestart.BASE_LANGUAGE;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;

import io.quarkus.devtools.codestarts.core.CodestartSpec;
import io.quarkus.devtools.codestarts.core.GenericCodestartCatalog;

public final class CodestartCatalogLoader {

    private static final ObjectMapper YAML_MAPPER = new ObjectMapper(new YAMLFactory())
            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
            .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
            .enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
            .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

    private CodestartCatalogLoader() {
    }

    public static void persist(CodestartSpec codestart, Path path) throws IOException {
        Files.createDirectories(path.getParent());
        try (BufferedWriter writer = Files.newBufferedWriter(path)) {
            YAML_MAPPER.writerFor(CodestartSpec.class).writeValue(writer, codestart);
        }
    }

    public static CodestartCatalog loadDefaultCatalog(CodestartPathLoader pathLoader,
            String first,
            String... more)
            throws IOException {
        final List codestarts = loadCodestarts(pathLoader, first, more);
        return new GenericCodestartCatalog<>(codestarts);
    }

    public static Collection loadCodestartsFromDir(Path directory)
            throws IOException {
        return loadCodestarts(new DirectoryCodestartPathLoader(directory), "");
    }

    public static List loadCodestarts(CodestartPathLoader pathLoader, String first, String... more)
            throws IOException {
        final List codestarts = new ArrayList<>(loadCodestarts(pathLoader, first));
        if (more != null) {
            for (String subDir : more) {
                codestarts.addAll(loadCodestarts(pathLoader, subDir));
            }
        }
        return codestarts;
    }

    // Visible for testing
    static Collection loadCodestarts(final CodestartPathLoader pathLoader, final String directoryName)
            throws IOException {
        try {
            return pathLoader.loadResourceAsPath(directoryName,
                    path -> {
                        try (final Stream pathStream = Files.walk(path)) {
                            return pathStream
                                    .filter(p -> p.getFileName().toString().matches("codestart\\.yml$"))
                                    .map(p -> {
                                        final String resourceName = resolveResourceName(directoryName, path, p);
                                        try {
                                            final CodestartSpec spec = readCodestartSpec(new String(Files.readAllBytes(p)));
                                            final String resourceCodestartDirectory = resourceName.replaceAll(
                                                    "/?codestart\\.yml",
                                                    "");
                                            return new Codestart(
                                                    new PathCodestartResourceAllocator(pathLoader, resourceCodestartDirectory),
                                                    spec,
                                                    resolveImplementedLanguages(p.getParent()));
                                        } catch (IOException e) {
                                            throw new CodestartStructureException(
                                                    "Failed to load codestart spec: " + resourceName,
                                                    e);
                                        }
                                    }).collect(Collectors.toList());
                        }
                    });
        } catch (IOException e) {
            return Collections.emptyList();
        }
    }

    private static Set resolveImplementedLanguages(Path p) throws IOException {
        // empty means all
        try (final Stream files = Files.list(p)) {
            return files
                    .filter(Files::isDirectory)
                    .map(CodestartCatalogLoader::getDirName)
                    .filter(l -> !Objects.equals(l, BASE_LANGUAGE))
                    .collect(Collectors.toSet());
        }
    }

    // Visible for testing
    static CodestartSpec readCodestartSpec(String content) throws com.fasterxml.jackson.core.JsonProcessingException {
        return YAML_MAPPER.readerFor(CodestartSpec.class)
                .readValue(content);
    }

    // Visible for testing
    static String getDirName(Path d) {
        return d.getFileName().toString().replaceAll("([/\\\\])$", "");
    }

    // Visible for testing
    static String resolveResourceName(final String dirName, final Path dirPath, final Path resourcePath) {
        return getResourcePath(dirName, dirPath.relativize(resourcePath).toString());
    }

    // Visible for testing
    static String getResourcePath(String first, String... more) {
        return Paths.get(first, more).toString().replace('\\', '/');
    }

    private static class PathCodestartResourceAllocator implements Codestart.CodestartResourceAllocator {

        private final CodestartPathLoader pathLoader;
        private final String resourceName;

        public PathCodestartResourceAllocator(CodestartPathLoader pathLoader, String resourceName) {
            this.pathLoader = pathLoader;
            this.resourceName = resourceName;
        }

        @Override
        public void allocate(Consumer readerConsumer) {
            try {
                pathLoader.loadResourceAsPath(resourceName, p -> {
                    readerConsumer.accept(new CodestartResource.PathCodestartResource(p));
                    return null;
                });
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
    }

    private static class DirectoryCodestartPathLoader implements CodestartPathLoader {

        private final Path dir;

        public DirectoryCodestartPathLoader(Path dir) {
            this.dir = dir;
        }

        @Override
        public  T loadResourceAsPath(String name, PathConsumer consumer) throws IOException {
            return consumer.consume(dir.resolve(name));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy