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

io.github.seniortesting.grpc.protoc.GrpcTools Maven / Gradle / Ivy

The newest version!
package io.github.seniortesting.grpc.protoc;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.commons.lang3.time.StopWatch;
import org.w3c.dom.NodeList;
import io.github.seniortesting.core.exception.SparrowException;
import io.github.seniortesting.core.util.CommandLines;
import io.github.seniortesting.core.util.FilesExt;
import io.github.seniortesting.core.util.StringsExt;
import io.github.seniortesting.core.util.Xmls;
import lombok.extern.slf4j.Slf4j;


/**
 * A simple wrapped grpc tool to compile the .proto files to java source code using protoc
 *
 * @author Walter Hu
 * Limit: Not support for grpc custom plugin
 */
@Slf4j
public class GrpcTools {
    private static GrpcTools grpcTools = null;
    private static final String DEFAULT_PROTO_ROOT_FOLDER =
            System.getProperty("user.home") + File.separator + ".grpc-proto";
    private static final String DEFAULT_PROTOC_ROOT_FOLDER =
            System.getProperty("user.home") + File.separator + ".grpc-proto";
    // protoc, protoc-gen-grpc-java files for protoc compile
    private String DEFAULT_PROTOC_VERSION = "LATEST";
    private String DEFAULT_GRPC_VERSION = "LATEST";
    // NOTE: DEFAULT_PROTO_COMMON_VERSION bind with the GRPC version
    private String DEFAULT_PROTO_COMMON_VERSION = "LATEST";
    private static final String LATEST_VERSION_FLAG = "LATEST";

    private static final String DEFAULT_SOURCE_FOLDER = "proto-dependencies";
    private static final String DEFAULT_PROTO_SOURCE_FOLDER =
            DEFAULT_PROTO_ROOT_FOLDER + File.separator + DEFAULT_SOURCE_FOLDER;
    private static final String DEFAULT_GIT_BRANCH = "develop";
    private static final String DEFAULT_PROTO_SOURCE_ROOT = "src/main/proto";
    private static final String PROTO_PROTO_FILTER = ".proto";

    private static final String DEFAULT_PROTOC_PLUGIN_FOLDER =
            DEFAULT_PROTOC_ROOT_FOLDER + File.separator + "protoc-plugins";
    private static final String DEFAULT_PROTOC_DEPENDENCIES_FOLDER =
            DEFAULT_PROTOC_ROOT_FOLDER + File.separator + "protoc-dependencies";
    private static final String DEFAULT_FILE_DESCRIPTOR_SET_FOLDER =
            DEFAULT_PROTOC_ROOT_FOLDER + File.separator + "proto-descriptor-sets";
    // this path should be the same as {@link io.github.grpc.core.constants.DescriptorFile }
    private static final String DEFAULT_FILE_DESCRIPTOR_SET =
            DEFAULT_FILE_DESCRIPTOR_SET_FOLDER + File.separator + "grpc-proto.pb";
    // download urls:
    // for china user, please use this maven mirror url: https://maven.aliyun.com/repository/public
    private static final String DEFAULT_MAVEN_MIRROR = "https://maven.aliyun.com/repository/public";
    private static final String URL_SEPARATOR = "/";
    private static final String MAVEN_METADATA = "maven-metadata.xml";
    private static final String RELEASE_VERSION_NODE_XPATH = "//metadata/versioning/release";

    private static final String PROTOC_URL =
            "%s/com/google/protobuf/protoc/";
    private static final String PROTOC_EXECUTABLE = "protoc-%s-%s.exe";
    private static final String PROTOC_PLUGIN_URL =
            "%s/io/grpc/protoc-gen-grpc-java/";
    private static final String PROTOC_PLUGIN_EXECUTABLE = "protoc-gen-grpc-java-%s-%s.exe";
    private static final String PROTOBUF_URL =
            "%s/com/google/protobuf/protobuf-java/";
    private static final String PROTOBUF_EXECUTABLE = "protobuf-java-%s.jar";
    private static final String PROTO_COMMON_URL =
            "%s/com/google/api/grpc/proto-google-common-protos/";
    private static final String PROTO_COMMON_EXECUTABLE = "proto-google-common-protos-%s.jar";
    private static final String DEFAULT_INCLUDES = "**/*.proto*";

    private int corePoolSize = 2;
    private int maxPoolSize = 10;
    private int keepAliveTime = 60;
    private int queueCapacity = 200;
    private String threadNamePrefix = "protoc-thread-%d";
    private ExecutorService executorService;

    public static GrpcTools getInstance() {
        if (null == grpcTools) {
            grpcTools = new GrpcTools();
        }
        grpcTools.initThreadPoolExecutor();
        return grpcTools;
    }

    private void initThreadPoolExecutor() {
        final BasicThreadFactory threadFactory = new BasicThreadFactory.Builder()
                .namingPattern(threadNamePrefix)
                .daemon(true)
                .priority(Thread.MAX_PRIORITY).build();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity),
                threadFactory);
        threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        this.executorService = threadPoolExecutor;
    }

    private Path cloneProtoRepository(String gitRepoUrl) {
        return cloneProtoRepository(gitRepoUrl, DEFAULT_GIT_BRANCH);
    }

    private Path cloneProtoRepository(String gitRepoUrl, String branch) {
        Path defaultProtoFolder = Path.of(DEFAULT_PROTO_SOURCE_FOLDER);
        return cloneProtoRepository(gitRepoUrl, branch, defaultProtoFolder);
    }

    private Path cloneProtoRepository(String gitRepoUrl, Path outputPath) {
        return cloneProtoRepository(gitRepoUrl, DEFAULT_GIT_BRANCH, outputPath);
    }

    /**
     * git clone the proto files repository firstly
     *
     * @param gitRepoUrl
     */
    private Path cloneProtoRepository(String gitRepoUrl, String branch, Path outputPath) {
        Path tempCloneDirectory = null;
        try {
            tempCloneDirectory = Files.createTempDirectory(DEFAULT_SOURCE_FOLDER);
            // first delete the existing files, always download source files
            final StopWatch stopWatch = StopWatch.createStarted();
            String tempFileAbsolutePath = tempCloneDirectory.normalize().toAbsolutePath().toString();
            // clone protoc git code
            final List cloneCommandList = List.of("git", "clone", "-b", branch, gitRepoUrl,
                    tempFileAbsolutePath);
            try {
                final String commandStr = cloneCommandList.stream().map(String::toString)
                        .collect(Collectors.joining(" "));
                LOGGER.info(commandStr);
                final Process cloneProcess = CommandLines.exec(cloneCommandList);
                final int errCode = cloneProcess.waitFor();
                if (errCode != 0) {
                    final String execResult = CommandLines.getExecErrorResult(cloneProcess);
                    LOGGER.error("command execution exit code return {}", execResult);
                    throw new SparrowException(commandStr + " git clone command exit error");
                } else {
                    // copy clone files into current specified location
                    Path sourceRootPath = Path.of(tempFileAbsolutePath, DEFAULT_PROTO_SOURCE_ROOT);
                    FilesExt.copyDir(sourceRootPath, outputPath);
                }
                LOGGER.info("Git clone proto completed, time takes: {} seconds", stopWatch.getTime(TimeUnit.SECONDS));
            } catch (InterruptedException e) {
                LOGGER.error("Clone command exception:", e);
                throw new SparrowException(e);
            }
        } catch (IOException e) {
            LOGGER.error("Clone command IO exception:", e);
            throw new SparrowException(e);
        } finally {
            // delete the temp git files
            FilesExt.del(tempCloneDirectory.toFile());
        }
        return outputPath;
    }

    private Path downloadProtoc(ProtocType protocType) {
        return downloadProtoc(DEFAULT_MAVEN_MIRROR, protocType, Path.of(DEFAULT_PROTOC_PLUGIN_FOLDER));
    }

    private Path downloadProtoc(String mavenMirrorUrl, ProtocType protocType, Path outputDirectory) {
        if (protocType.equals(ProtocType.PROTOC)) {
            return downloadProtoc(
                    protocType,
                    mavenMirrorUrl,
                    PROTOC_URL,
                    DEFAULT_PROTOC_VERSION,
                    PROTOC_EXECUTABLE,
                    outputDirectory);
        } else if (protocType.equals(ProtocType.PROTOC_PLUGIN)) {
            return downloadProtoc(
                    protocType,
                    mavenMirrorUrl,
                    PROTOC_PLUGIN_URL,
                    DEFAULT_GRPC_VERSION,
                    PROTOC_PLUGIN_EXECUTABLE,
                    outputDirectory);
        } else if (protocType.equals(ProtocType.PROTOBUF)) {
            return downloadProtoc(
                    protocType,
                    mavenMirrorUrl,
                    PROTOBUF_URL,
                    DEFAULT_PROTOC_VERSION,
                    PROTOBUF_EXECUTABLE,
                    outputDirectory);
        } else if (protocType.equals(ProtocType.PROTO_COMMON)) {
            return downloadProtoc(
                    protocType,
                    mavenMirrorUrl,
                    PROTO_COMMON_URL,
                    DEFAULT_PROTO_COMMON_VERSION,
                    PROTO_COMMON_EXECUTABLE,
                    outputDirectory);
        } else {
            LOGGER.error("unsupported download type: {}", protocType.toString());
        }
        return null;
    }

    private Path downloadProtoc(
            ProtocType protocType,
            String mavenMirrorUrl,
            String protocDownloadUrl,
            String protocVersion,
            String protocExecutable,
            Path outputDirectory) {
        final String outputDirectoryPath = outputDirectory.normalize().toAbsolutePath().toString();
        String protocUrl = null;
        try {
            if (Files.notExists(outputDirectory)) {
                Files.createDirectories(outputDirectory);
            }
            if (!Files.isDirectory(outputDirectory)) {
                LOGGER.warn("download directory {} is not a directory ", outputDirectory);
                return null;
            }
            // if protocVersion not pass, will try to get the latest version
            if (protocVersion == null || protocVersion.equals("") || protocVersion.equals(LATEST_VERSION_FLAG)) {
                String metaDataUrl = String.format(protocDownloadUrl, mavenMirrorUrl) + MAVEN_METADATA;
                LOGGER.info("Version is {}, will try to build the latest protoc executable", protocVersion);
                final byte[] downloadBytes = FilesExt.UrlDownloader.downloadWithOkhttpSync(metaDataUrl);
                // metadata/versioning/release
                final NodeList nodeList = Xmls.parse(downloadBytes, RELEASE_VERSION_NODE_XPATH);
                if (Optional.ofNullable(nodeList).isPresent()) {
                    protocVersion = nodeList.item(0).getTextContent();
                } else {
                    LOGGER.error("Not found the node path: {} from uri: {}", RELEASE_VERSION_NODE_XPATH, metaDataUrl);
                    throw new SparrowException("Version fetch exception");
                }
            }
            //set the version fields
            if (protocType.equals(ProtocType.PROTOC)) {
                DEFAULT_PROTOC_VERSION = protocVersion;
            } else if (protocType.equals(ProtocType.PROTOC_PLUGIN)) {
                DEFAULT_GRPC_VERSION = protocVersion;
            } else if (protocType.equals(ProtocType.PROTO_COMMON)) {
                DEFAULT_PROTO_COMMON_VERSION = protocVersion;
            }
            Detector.detect();
            String DETECTED_CLASSIFIER = System.getProperty(Detector.DETECTED_CLASSIFIER);
            String executableName = String.format(protocExecutable, protocVersion, DETECTED_CLASSIFIER);
            Path protocExecutablePath = Paths.get(outputDirectoryPath, executableName);
            String saveAsExecutablePath = protocExecutablePath.normalize().toAbsolutePath().toString();
            if (Files.exists(protocExecutablePath)) {
                LOGGER.warn("Proto file exists in: {}", saveAsExecutablePath);
                makeFileExecutable(protocExecutablePath);
                return protocExecutablePath;
            }
            protocUrl =
                    String.format(protocDownloadUrl, mavenMirrorUrl)
                            + protocVersion + URL_SEPARATOR + executableName;
            LOGGER.info("Downloading file: {}", protocUrl);
            final StopWatch stopWatch = StopWatch.createStarted();
            FilesExt.UrlDownloader.downloadFileWithResume(protocUrl, saveAsExecutablePath);
            makeFileExecutable(protocExecutablePath);
            LOGGER.info("Download proto {} completed, time takes: {} seconds", executableName,
                    stopWatch.getTime(TimeUnit.SECONDS));
            return protocExecutablePath;
        } catch (Exception e) {
            LOGGER.error("Download proto exception, proto url {} ", protocUrl, e);
        }
        return null;
    }

    private void makeFileExecutable(Path file) {
        if (!Detector.isFamilyWindows()) {
            file.toFile().setReadable(true);
            file.toFile().setExecutable(true);
        }
    }

    private Path makeProtoPathFromJars(ProtobufType protobufType) {
        return makeProtoPathFromJars(protobufType, Path.of(DEFAULT_PROTO_SOURCE_FOLDER), true);
    }

    private Path makeProtoPathFromJars(ProtobufType protobufType, Path extractDirectory, boolean extractSamePath) {
        // two main jars need to add as protoc import path:
        // 1. https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/3.15.1/protobuf-java-3.15.1.jar
        // 2. https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-common-protos/2.0
        // download the jar file
        Path downloadJarPath = null;
        if (protobufType.equals(ProtobufType.PROTOBUF)) {
            downloadJarPath = downloadProtoc(ProtocType.PROTOBUF);
        } else if (protobufType.equals(ProtobufType.PROTO_COMMON)) {
            downloadJarPath = downloadProtoc(ProtocType.PROTO_COMMON);
        }
        if (Optional.ofNullable(downloadJarPath).isPresent()) {
            // extract the jar file for proto files
            // for some reason under IAM, we receive poms as dependent files
            // I am excluding .xml rather than including .jar as there may be other extensions in use (sar, har, zip)
            File classpathElementFile = downloadJarPath.toFile();
            if (classpathElementFile.isFile() && classpathElementFile.canRead() &&
                    !classpathElementFile.getName().endsWith(".xml")) {
                // create the jar file. the constructor validates.
                try (final JarFile classpathJar = new JarFile(classpathElementFile)) {
                    final Enumeration jarEntries = classpathJar.entries();
                    File jarDirectory;
                    if (extractSamePath) {
                        jarDirectory = new File(extractDirectory.normalize().toAbsolutePath().toString());
                    } else {
                        jarDirectory = new File(extractDirectory.normalize().toAbsolutePath().toString(),
                                truncatePath(classpathJar.getName()));
                        // clean the temporary directory to ensure that stale files aren't used
                        FilesExt.del(jarDirectory);
                    }
                    while (jarEntries.hasMoreElements()) {
                        final JarEntry jarEntry = jarEntries.nextElement();
                        final String jarEntryName = jarEntry.getName();
                        if (!jarEntry.isDirectory() && SelectorUtils
                                .matchPath(DEFAULT_INCLUDES, jarEntryName, "/", true)) {
                            try {
                                // Check for Zip Slip vulnerability
                                // https://snyk.io/research/zip-slip-vulnerability
                                final String canonicalJarDirectoryPath = jarDirectory.getCanonicalPath();
                                final File uncompressedCopy = new File(jarDirectory, jarEntryName);
                                final String canonicalUncompressedCopyPath = uncompressedCopy.getCanonicalPath();
                                if (!canonicalUncompressedCopyPath
                                        .startsWith(canonicalJarDirectoryPath + File.separator)) {
                                    throw new SparrowException(
                                            "ZIP SLIP: Entry " + jarEntry.getName() +
                                                    " in " + classpathJar.getName() + " is outside of the target dir");
                                }
                                Files.createDirectories(uncompressedCopy.getParentFile().toPath());
                                Files.copy(classpathJar.getInputStream(jarEntry), uncompressedCopy.toPath(),
                                        StandardCopyOption.REPLACE_EXISTING);
                            } catch (final IOException e) {
                                throw new SparrowException("Unable to unpack proto files", e);
                            }
                        }
                    }
                    return jarDirectory.toPath();
                } catch (final IOException e) {
                    throw new SparrowException(
                            "Not a readable JAR artifact: " + classpathElementFile.getAbsolutePath(), e);
                }
            }
        }
        return null;
    }

    /**
     * Truncates the path of jar files so that they are relative to the local repository.
     *
     * @param jarPath the full path of a jar file.
     * @return the truncated path relative to the local repository or root of the drive.
     */
    private String truncatePath(final String jarPath) {
        return StringsExt.md5(jarPath);
    }

    private boolean protocCompiler(
            Path protoPath,
            List protoPathElements,
            Path protocExecutablePath,
            Path protocGenGrpcJavaExecutablePath) {
        // clear old descriptorsFile
        final Path descriptorFile = Path.of(DEFAULT_FILE_DESCRIPTOR_SET);
        try {
            if (Files.exists(descriptorFile)) {
                Files.deleteIfExists(descriptorFile);
            }
            Files.createDirectories(descriptorFile.getParent());
        } catch (IOException e) {
        }

        final List compileCommand = new ArrayList<>();
        compileCommand.add(protocExecutablePath.normalize().toAbsolutePath().toString());
        try {
            final String protoRootFilePath = protoPath.normalize().toAbsolutePath().toString();
            // add "--proto_path=" + protoPathElement
            compileCommand.add("--proto_path=" + protoRootFilePath);
            for (final Path protoPathElement : protoPathElements) {
                compileCommand.add("--proto_path=" + protoPathElement.normalize().toAbsolutePath().toString());
            }
            // add --java_out=
            compileCommand.add("--java_out=" + protoRootFilePath);
            // command.add("--plugin=protoc-gen-grpc-java=' + pluginExecutable);
            // command.add("--grpc-java_out=" + javaOutputDirectory);
            if (Optional.ofNullable(protocGenGrpcJavaExecutablePath).isPresent()) {
                compileCommand.add("--plugin=protoc-gen-grpc-java=" + protocGenGrpcJavaExecutablePath);
                compileCommand.add("--grpc-java_out=" + protoRootFilePath);
            }
            // add proto path one by one
            final List protoFiles = FilesExt
                    .listFiles(protoPath, path -> path.toFile().getName().endsWith(PROTO_PROTO_FILTER));
            for (final String protoFile : protoFiles) {
                compileCommand.add(protoFile);
            }
            // command.add("--descriptor_set_out=" + descriptorSetFile);
            compileCommand.add("--descriptor_set_out=" + DEFAULT_FILE_DESCRIPTOR_SET);
            // command.add("--include_imports");
            // command.add("--include_source_info");
            final StopWatch stopWatch = StopWatch.createStarted();
            final Process commandProcess = CommandLines.exec(compileCommand);
            final int errCode = commandProcess.waitFor();
            LOGGER.info("protoc compile completed, time takes: {} seconds", stopWatch.getTime(TimeUnit.SECONDS));
            boolean commandSuccess = (errCode == 0);
            if (!commandSuccess) {
                final String execErrorResult = CommandLines.getExecErrorResult(commandProcess);
                LOGGER.error("command execution exit code return {}", execErrorResult);
            }
            return commandSuccess;
        } catch (InterruptedException e) {
            LOGGER.error("Clone command exception:", e);
            throw new SparrowException(e);
        }
    }

    private void addClassPaths(Path protoPath)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, MalformedURLException {
        final URL url = protoPath.toUri().toURL();
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        URLClassLoader urlClassLoader = null;
        if (classLoader instanceof URLClassLoader) {
            urlClassLoader = (URLClassLoader) classLoader;
        } else {
        }
        if (Optional.ofNullable(urlClassLoader).isPresent()) {
            Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
            method.setAccessible(true);
            method.invoke(urlClassLoader, new Object[] { url });
        }
    }

    public void compile(String protoGitRepoUrl) {
        compile(protoGitRepoUrl, DEFAULT_GIT_BRANCH);
    }

    public void compile(String protoGitRepoUrl, String branch) {
        final List protocPaths = new ArrayList<>();
        final StopWatch stopWatch = StopWatch.createStarted();
        Callable cloneRepoThread = () -> cloneProtoRepository(protoGitRepoUrl, branch);
        Callable protocDownloadThread = () -> downloadProtoc(ProtocType.PROTOC);
        Callable protocPluginDownloadThread = () -> downloadProtoc(ProtocType.PROTOC_PLUGIN);
        Callable protobufDownloadThread = () -> makeProtoPathFromJars(ProtobufType.PROTOBUF);
        Callable protoCommonDownloadThread = () -> makeProtoPathFromJars(ProtobufType.PROTO_COMMON);
        final List> downloadThreadList = List.of(
                cloneRepoThread,
                protocDownloadThread,
                protocPluginDownloadThread,
                protobufDownloadThread,
                protoCommonDownloadThread);
        try {
            final List> futureList = grpcTools.executorService.invokeAll(downloadThreadList);
            for (final Future future : futureList) {
                final Path path = future.get();
                protocPaths.add(path);
            }
        } catch (InterruptedException e) {
            LOGGER.error("timeout download: ", e);
        } catch (ExecutionException e) {
            LOGGER.error("execution exception: ", e);
        }
        // compile protoc
        final boolean allMatch = protocPaths.stream().findAny().stream().allMatch(path -> Objects.nonNull(path));
        if (protocPaths.size() == downloadThreadList.size() && allMatch) {
            Detector.detect();
            String DETECTED_CLASSIFIER = System.getProperty(Detector.DETECTED_CLASSIFIER);
            String protocExecutableName = String.format(PROTOC_EXECUTABLE, DEFAULT_PROTOC_VERSION,
                    DETECTED_CLASSIFIER);
            String protocPluginExecutableName = String
                    .format(PROTOC_PLUGIN_EXECUTABLE, DEFAULT_GRPC_VERSION,
                            DETECTED_CLASSIFIER);
            Path cloneProtoPath =
                    protocPaths.stream()
                            .filter(path -> path.equals(Path.of(DEFAULT_PROTO_SOURCE_FOLDER)))
                            .findFirst().orElse(null);
            Path downloadProtocPath =
                    protocPaths.stream()
                            .filter(path -> path.normalize().toAbsolutePath().endsWith(protocExecutableName))
                            .findFirst().orElse(null);
            Path downloadProtocPluginPath =
                    protocPaths.stream()
                            .filter(path -> path.normalize().toAbsolutePath().endsWith(protocPluginExecutableName))
                            .findFirst().orElse(null);
            Set protoPathElements =
                    protocPaths.stream()
                            .filter(path -> path.normalize().toAbsolutePath().toString()
                                    .contains(DEFAULT_PROTO_SOURCE_FOLDER))
                            .collect(Collectors.toSet());
            if (Optional.ofNullable(downloadProtocPath).isPresent()
                    && Optional.ofNullable(downloadProtocPluginPath).isPresent()
                    && protoPathElements.size() == 1) {
                final boolean protocCompilerResult =
                        protocCompiler(cloneProtoPath,
                                protoPathElements.stream().collect(Collectors.toList()),
                                downloadProtocPath,
                                downloadProtocPluginPath);
                LOGGER.info("Compile Info: \n - Proto Source Path: {}", cloneProtoPath);
                LOGGER.info("Compile success result is: {}, time takes {} seconds", protocCompilerResult,
                        stopWatch.getTime(TimeUnit.SECONDS));
            } else {
                LOGGER.error("Compile check executable file not found!");
            }
        }
    }

    public String getFileDescriptorSet() {
        return DEFAULT_FILE_DESCRIPTOR_SET;
    }

    /**
     * The protoc type
     *
     * @author Walter Hu
     */
    public enum ProtocType {
        /**
         * inspect the download type
         */
        PROTOC,
        PROTOC_PLUGIN,
        PROTOBUF,
        PROTO_COMMON;
    }

    /**
     * The download protobuf common libraries type
     *
     * @author Walter Hu
     */
    public enum ProtobufType {
        /**
         * inspect the download type
         */
        PROTOBUF,
        PROTO_COMMON;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy