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

io.micronaut.starter.cli.command.CreateLambdaBuilderCommand Maven / Gradle / Ivy

There is a newer version: 4.7.0
Show newest version
/*
 * Copyright 2017-2023 original 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
 *
 * https://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.micronaut.starter.cli.command;

import io.micronaut.context.annotation.Prototype;
import io.micronaut.context.exceptions.ConfigurationException;
import io.micronaut.core.util.StringUtils;
import io.micronaut.starter.application.ApplicationType;
import io.micronaut.starter.application.generator.ProjectGenerator;
import io.micronaut.starter.feature.Feature;
import io.micronaut.starter.feature.architecture.Arm;
import io.micronaut.starter.feature.architecture.CpuArchitecture;
import io.micronaut.starter.feature.architecture.X86;
import io.micronaut.starter.feature.aws.AmazonApiGateway;
import io.micronaut.starter.feature.aws.AwsApiFeature;
import io.micronaut.starter.feature.aws.AwsLambdaFeatureValidator;
import io.micronaut.starter.feature.aws.Cdk;
import io.micronaut.starter.feature.aws.LambdaFunctionUrl;
import io.micronaut.starter.feature.aws.LambdaTrigger;
import io.micronaut.starter.feature.function.awslambda.AwsLambda;
import io.micronaut.starter.feature.graalvm.GraalVM;
import io.micronaut.starter.feature.graalvm.GraalVMFeatureValidator;
import io.micronaut.starter.options.BuildTool;
import io.micronaut.starter.options.JdkVersion;
import io.micronaut.starter.options.Language;
import io.micronaut.starter.options.Options;
import io.micronaut.starter.options.TestFramework;
import org.jline.reader.LineReader;
import picocli.CommandLine;

import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;


@CommandLine.Command(name = CreateLambdaBuilderCommand.NAME, description = "A guided walk-through to create an lambda function")
@Prototype
public class CreateLambdaBuilderCommand extends BuilderCommand {

    public static final String NAME = "create-aws-lambda";

    public CreateLambdaBuilderCommand(
            ProjectGenerator projectGenerator,
            List features
    ) {
        super(projectGenerator, features);
    }

    @Override
    public GenerateOptions createGenerateOptions(LineReader reader) {
        Set applicationFeatures = new HashSet<>();
        applicationFeatures.add(AwsLambda.FEATURE_NAME_AWS_LAMBDA);
        CodingStyle codingStyle = getCodingStyle(reader);
        ApplicationType applicationType = applicationTypeForCodingStyle(codingStyle);
        if (codingStyle == CodingStyle.CONTROLLERS) {
            Feature apiFeature = getApiTrigger(applicationType, reader);
            applicationFeatures.add(apiFeature.getName());
        } else {
            Feature trigger = getTrigger(reader);
            applicationFeatures.add(trigger.getName());
        }

        LambdaDeployment deployment = getLambdaDeployment(reader);
        if (deployment == LambdaDeployment.NATIVE_EXECUTABLE) {
            applicationFeatures.add(GraalVM.FEATURE_NAME_GRAALVM);
        }

        getArchitecture(reader).ifPresent(architecture -> {
            if (architecture instanceof Arm) {
                applicationFeatures.add(Arm.NAME);
            } else if (architecture instanceof X86) {
                applicationFeatures.add(X86.NAME);
            }
        });

        getCdk(reader).ifPresent(f -> applicationFeatures.add(f.getName()));

        Language language = getLanguage(deployment, reader);
        TestFramework testFramework = getTestFramework(reader, language);
        BuildTool buildTool = getBuildTool(reader, language);
        JdkVersion jdkVersion = getJdkVersion(reader);
        Options options = new Options(language, testFramework, buildTool, jdkVersion);
        return new GenerateOptions(applicationType, options, applicationFeatures);
    }

    @Override
    protected List getJdkVersionCandidates() {
        return AwsLambdaFeatureValidator.supportedJdks().stream()
                .map(JdkVersion::majorVersion)
                .map(String::valueOf)
                .toList();
    }

    protected ApplicationType applicationTypeForCodingStyle(CodingStyle codingStyle) {
        switch (codingStyle) {
            case HANDLER:
                return ApplicationType.FUNCTION;
            case CONTROLLERS:
            default:
                return ApplicationType.DEFAULT;

        }
    }

    static Language[] languagesForDeployment(LambdaDeployment deployment) {
        return deployment == LambdaDeployment.NATIVE_EXECUTABLE ?
                Stream.of(Language.values())
                        .filter(GraalVMFeatureValidator::supports)
                        .toArray(Language[]::new) :
                Language.values();
    }

    protected Feature getApiTrigger(ApplicationType applicationType, LineReader reader) {
        Feature defaultFeature = features.stream().filter(AmazonApiGateway.class::isInstance).findFirst()
                .orElseThrow(() -> new ConfigurationException("default feature " + LambdaFunctionUrl.NAME + " not found"));
        out("Choose your trigger. (enter for " + defaultFeature.getTitle() + ")");
        return getFeatureOption(
                apiTriggerFeatures(applicationType, features),
                Feature::getTitle,
                defaultFeature,
                reader);
    }

    protected Feature getTrigger(LineReader reader) {
        Feature defaultFeature = features.stream().filter(LambdaFunctionUrl.class::isInstance).findFirst()
                .orElseThrow(() -> new ConfigurationException("default feature " + LambdaFunctionUrl.NAME + " not found"));
        out("Choose your trigger. (enter for " + defaultFeature.getTitle() + ")");
        return getFeatureOption(
                triggerFeatures(features),
                Feature::getTitle,
                defaultFeature,
                reader);
    }

    protected Optional getArchitecture(LineReader reader) {
        List cpuArchitecturesFeatures = features.stream()
                .filter(CpuArchitecture.class::isInstance)
                .toList();
        String defaultCpuArchitecture = X86.NAME;
        out("Choose your Lambda Architecture. (enter for " + defaultCpuArchitecture + ")");
        String option = getListOption(
                cpuArchitecturesFeatures.stream()
                        .map(Feature::getName)
                        .sorted()
                        .toList(),
                o -> o,
                defaultCpuArchitecture,
                reader);
        return cpuArchitecturesFeatures
                .stream()
                .filter(f -> f.getName().equals(option))
                .findFirst();
    }

    protected Language getLanguage(LambdaDeployment deployment, LineReader reader) {
        out("Choose your preferred language. (enter for default)");
        return getEnumOption(
                languagesForDeployment(deployment),
                language -> StringUtils.capitalize(language.getName()),
                Language.DEFAULT_OPTION,
                reader);
    }

    protected LambdaDeployment getLambdaDeployment(LineReader reader) {
        out("How do you want to deploy?. (enter for Java runtime)");
        return getEnumOption(
                LambdaDeployment.class,
                LambdaDeployment::getDescription,
                LambdaDeployment.FAT_JAR,
                reader);
    }

    protected CodingStyle getCodingStyle(LineReader reader) {
        out("How do you want to write your application? (enter for Controllers)");
        return getEnumOption(
                CodingStyle.class,
                CodingStyle::getDescription,
                CodingStyle.CONTROLLERS,
                reader);
    }

    protected Optional getCdk(LineReader reader) {
        out("Do you want to generate infrastructure as code with CDK? (enter for yes)");
        return getYesOrNo(reader) == YesOrNo.YES
                ? features.stream().filter(Cdk.class::isInstance).findFirst()
                : Optional.empty();
    }

    static List apiTriggerFeatures(ApplicationType applicationType, Collection features) {
        return features.stream()
                .filter(AwsApiFeature.class::isInstance)
                .filter(f -> f.supports(applicationType))
                .sorted(Comparator.comparing(Feature::getTitle).reversed())
                .toList();
    }

    static List triggerFeatures(Collection features) {
        return features.stream()
                .filter(LambdaTrigger.class::isInstance)
                .sorted((o1, o2) -> {
                    if (o1 instanceof AwsApiFeature && (o2 instanceof AwsApiFeature)) {
                        return o2.getTitle().compareTo(o1.getTitle());
                    }
                    if (o1 instanceof AwsApiFeature) {
                        return -1;
                    }
                    if (o2 instanceof AwsApiFeature) {
                        return 1;
                    }
                    return o1.getTitle().compareTo(o2.getTitle());
                })
                .toList();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy