com.microsoft.alm.plugin.external.tools.TfTool.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.alm.plugin.external.tools.TfTool.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root.

package com.microsoft.alm.plugin.external.tools;

import com.microsoft.alm.client.utils.StringUtil;
import com.microsoft.alm.common.utils.SystemHelper;
import com.microsoft.alm.plugin.external.commands.TfVersionCommand;
import com.microsoft.alm.plugin.external.exceptions.ToolBadExitCodeException;
import com.microsoft.alm.plugin.external.exceptions.ToolException;
import com.microsoft.alm.plugin.external.exceptions.ToolVersionException;
import com.microsoft.alm.plugin.external.models.ToolVersion;
import com.microsoft.alm.plugin.services.PluginServiceProvider;
import com.microsoft.alm.plugin.services.PropertyService;
import com.sun.jna.Platform;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

/**
 * This is a static class that provides helper methods for running the TF command line.
 */
public class TfTool {
    private static final Logger logger = LoggerFactory.getLogger(TfTool.class);

    private static final String[] TF_WINDOWS_PROGRAMS = { "tf.exe", "tf.bat", "tf.cmd" };
    private static final String[] TF_OTHER_PROGRAMS = { "tf", "tf.sh" };
    private static ToolVersion cachedVersion = null;
    public static final ToolVersion TF_MIN_VERSION = new ToolVersion("14.0.3");
    public static final String TF_DIRECTORY_PREFIX = "TEE-CLC";
    private static final String PATH_ENV = "PATH";
    private static final String TF_HOME_ENV = "TF_HOME";
    private static final String SYSTEM_DRIVE = SystemHelper.getEnvironmentVariable("SystemDrive");

    // standard unix paths to check (Git uses similar ones for both Linux/Unix/Mac)
    private static final File[] UNIX_PATHS = { new File("/opt/local/opt"), new File("/opt"), new File("/sbin"),
            new File("/usr/share"), new File("/usr/sbin"), new File("/usr/local/opt"), new File("/usr/local/share"),
            new File("/usr/local") };

    private static File[] PROGRAM_FILE_PATHS = { new File(SYSTEM_DRIVE, "Program Files"),
            new File(SYSTEM_DRIVE, "Program Files (x86)"), new File(SYSTEM_DRIVE, "Program Files\\Java") };

    /**
     * This method returns the path to the TF command line program.
     * It relies on the vsts-settings file.
     * This method will throw if no valid path exists.
     */
    public static String getValidLocation() {
        // Get the tf command location from file
        final String location = getLocation();
        if (StringUtil.isNullOrEmpty(location)) {
            // tfHome property not set
            throw new ToolException(ToolException.KEY_TF_HOME_NOT_SET);
        }

        final String[] filenames = Platform.isWindows() ? TF_WINDOWS_PROGRAMS : TF_OTHER_PROGRAMS;

        // Verify the path leads to a tf command and exists
        for (final String filename : filenames) {
            if (StringUtils.endsWith(location, filename) && (new File(location)).exists()) {
                return location;
            }
        }

        // The saved location does not point to the tf command
        throw new ToolException(ToolException.KEY_TF_EXE_NOT_FOUND);
    }

    /**
     * This method returns the path to the TF command line program that was saved in the properties file
     */
    public static String getLocation() {
        // Get the location of the TF command from the properties files
        return PluginServiceProvider.getInstance().getPropertyService().getProperty(PropertyService.PROP_TF_HOME);
    }

    /**
     * Determines the version of the TF command being used and throws if the version is too small.
     */
    public static void checkVersion() {
        final TfVersionCommand command = new TfVersionCommand();
        cachedVersion = command.runSynchronously();
        if (cachedVersion.compare(TF_MIN_VERSION) < 0) {
            throw new ToolVersionException(cachedVersion, TF_MIN_VERSION);
        }
    }

    public static ToolVersion getCachedVersion() {
        return cachedVersion;
    }

    /**
     * Use this method to check the TF exit code and throw an appropriate exception.
     */
    public static void throwBadExitCode(final int exitCode) {
        if (exitCode != 0) {
            // TODO distinguish between warnings and fatal errors
            throw new ToolBadExitCodeException(exitCode);
        }
    }

    /**
     * Try to find the tf command by checking common places based on the OS
     *
     * @return
     */
    public static String tryDetectTf() {
        final String[] exeNames = Platform.isWindows() ? TF_WINDOWS_PROGRAMS : TF_OTHER_PROGRAMS;
        final File[] filePaths = Platform.isWindows() ? PROGRAM_FILE_PATHS : UNIX_PATHS;
        return tryDetectTf(exeNames, filePaths);
    }

    protected static String tryDetectTf(final String[] exeNames, final File[] filePaths) {
        try {
            // try looking at env path
            String exe = checkTfPath(SystemHelper.getEnvironmentVariable(TF_HOME_ENV), exeNames);
            if (StringUtils.isNotEmpty(exe)) {
                logger.debug("Found exe by TF_HOME: " + exe);
                return exe;
            }

            // try looking at PATH
            exe = getExeFromPath(exeNames);
            if (StringUtils.isNotEmpty(exe)) {
                logger.debug("Found exe by PATH: " + exe);
                return exe;
            }

            exe = searchDirectories(filePaths, exeNames);
            if (StringUtils.isNotEmpty(exe)) {
                logger.debug("Found exe by Program Files: " + exe);
                return exe;
            }
        } catch (Exception e) {
            // swallow all errors since it's not essential we find the exe
            logger.warn("Error while detecting tf exe", e);
        }

        logger.warn("No tf command was detected");
        return null;
    }

    /**
     * Check if PATH contains the path to the tf command
     *
     * @return
     */
    private static String getExeFromPath(final String[] exeNames) {
        final String envPath = SystemHelper.getEnvironmentVariable(PATH_ENV);

        if (StringUtils.isNotEmpty(envPath)) {
            final String[] paths = envPath.split(";");
            for (final String path : paths) {
                final File filePath = new File(path);
                if (StringUtils.startsWith(filePath.getName(), TF_DIRECTORY_PREFIX) && filePath.isDirectory()) {
                    final String verifiedPath = checkTfPath(filePath.getPath(), exeNames);
                    if (verifiedPath != null) {
                        return verifiedPath;
                    }
                }
            }
        }
        return null;
    }

    /**
     * Search thru given directories to find one of the given acceptable tf commands
     *
     * @param paths
     * @param exeNames
     * @return
     */
    private static String searchDirectories(final File[] paths, final String[] exeNames) {
        for (final File path : paths) {
            if (path.exists()) {
                for (final File subDirectory : path.listFiles()) {
                    if (StringUtils.startsWith(subDirectory.getName(), TF_DIRECTORY_PREFIX)
                            && subDirectory.isDirectory()) {
                        final String verifiedPath = checkTfPath(subDirectory.getPath(), exeNames);
                        if (verifiedPath != null) {
                            return verifiedPath;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * Checks if the given path contains one of the given acceptable tf commands
     *
     * @param exePath
     * @param exeNames
     * @return
     */
    private static String checkTfPath(final String exePath, final String[] exeNames) {
        if (StringUtils.isNotEmpty(exePath)) {
            for (final String filename : exeNames) {
                final File tfFile = new File(exePath, filename);
                if (tfFile.exists()) {
                    return tfFile.toString();
                }
            }
        }
        return null;
    }
}