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

org.eclipse.jkube.kit.common.util.EnvUtil Maven / Gradle / Ivy

/**
 * Copyright (c) 2019 Red Hat, Inc.
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at:
 *
 *     https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   Red Hat, Inc. - initial API and implementation
 */
package org.eclipse.jkube.kit.common.util;

import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;

/**
 * @author roland
 * @since 24.05.17
 */
public class EnvUtil {

    public static final String MAVEN_PROPERTY_REGEXP = "\\s*\\$\\{\\s*([^}]+)\\s*}\\s*$";

    // Standard HTTP port (IANA registered). It is used only in older docker installations.
    public static final String DOCKER_HTTP_PORT = "2375";

    public static final String PROPERTY_COMBINE_POLICY_SUFFIX = "_combine";
    private static final String COMMA = ",";
    private static final String WHITESPACE = " ";
    private static final String COMMA_WHITESPACE = COMMA + WHITESPACE;

    private EnvUtil() {
    }

    // Convert docker host URL to an HTTP(s) URL
    public static String convertTcpToHttpUrl(String connect) {
        String protocol = connect.contains(":" + DOCKER_HTTP_PORT) ? "http:" : "https:";
        return connect.replaceFirst("^tcp:", protocol);
    }

    /**
     * Compare to version strings and return the larger version strings. This is used in calculating
     * the minimal required API version for this plugin. Version strings must be comparable as floating numbers.
     * The versions must be given in the format in a semantic version format (e.g. "1.23"
     * 

If either version is null, the other version is returned (which can be null as well) * * @param versionA first version number * @param versionB second version number * @return the larger version number */ public static String extractLargerVersion(String versionA, String versionB) { if (versionB == null || versionA == null) { return versionA == null ? versionB : versionA; } else { String[] partsA = versionA.split("\\."); String[] partsB = versionB.split("\\."); for (int i = 0; i < (partsA.length < partsB.length ? partsA.length : partsB.length); i++) { int pA = Integer.parseInt(partsA[i]); int pB = Integer.parseInt(partsB[i]); if (pA > pB) { return versionA; } else if (pB > pA) { return versionB; } } return partsA.length > partsB.length ? versionA : versionB; } } /** * Check whether the first given API version is larger or equals the second given version * * @param versionA first version to check against * @param versionB the second version * @return true if versionA is greater or equals versionB, false otherwise */ public static boolean greaterOrEqualsVersion(String versionA, String versionB) { String largerVersion = extractLargerVersion(versionA, versionB); return largerVersion != null && largerVersion.equals(versionA); } private static final Function SPLIT_ON_LAST_COLON = element -> { int colon = element.lastIndexOf(':'); if (colon < 0) { return new String[]{element, element}; } else { return new String[]{element.substring(0, colon), element.substring(colon + 1)}; } }; /** * Splits every element in the given list on the last colon in the name and returns a list with * two elements: The left part before the colon and the right part after the colon. If the string * doesn't contain a colon, the value is used for both elements in the returned arrays. * * @param listToSplit list of strings to split * @return return list of 2-element arrays or an empty list if the given list is empty or null */ public static List splitOnLastColon(List listToSplit) { if (listToSplit != null) { return listToSplit.stream().map(SPLIT_ON_LAST_COLON).collect(Collectors.toList()); } return Collections.emptyList(); } private static final Function> COMMA_SPLITTER = input -> Arrays.stream(input.split(COMMA)) .filter(StringUtils::isNotBlank) .map(StringUtils::trim) .collect(Collectors.toList()); /** * Remove empty members of a list. * * @param input A list of String * @return A list of Non-Empty (length ;> 0) String */ @Nonnull public static List removeEmptyEntries(@Nullable List input) { if (input == null) { return Collections.emptyList(); } return input.stream().filter(StringUtils::isNotBlank).map(StringUtils::trim).collect(Collectors.toList()); } /** * Split each element of an Iterable;<String;> at commas. * * @param input Iterable over strings. * @return An Iterable over string which breaks down each input element at comma boundaries */ @Nonnull public static List splitAtCommasAndTrim(Iterable input) { if (input == null) { return Collections.emptyList(); } return StreamSupport.stream(input.spliterator(), false) .filter(StringUtils::isNotBlank).map(COMMA_SPLITTER).flatMap(Collection::stream) .collect(Collectors.toList()); } public static String[] splitOnSpaceWithEscape(String toSplit) { String[] split = toSplit.split("(? NOTE: If key is "._combine" ({@link #PROPERTY_COMBINE_POLICY_SUFFIX}) it is ignored! This is reserved for combine policy tweaking. * * @param prefix prefix which specifies the part which should be extracted as map * @param properties properties to extract from * @return the extracted map or null if no such map exists */ public static Map extractFromPropertiesAsMap(String prefix, Properties properties) { Map ret = new HashMap<>(); Enumeration names = properties.propertyNames(); String prefixP = prefix + "."; while (names.hasMoreElements()) { String propName = (String) names.nextElement(); if (propMatchesPrefix(prefixP, propName)) { String mapKey = propName.substring(prefixP.length()); if (PROPERTY_COMBINE_POLICY_SUFFIX.equals(mapKey)) { continue; } ret.put(mapKey, properties.getProperty(propName)); } } return ret.size() > 0 ? ret : null; } /** * Extract from given properties a list of string values. The prefix is used to determine the subset of the * given properties from which the list should be extracted, the rest is used as a numeric index. If the rest * is not numeric, the order is not determined (all those props are appended to the end of the list) * *

NOTE: If suffix/index is "._combine" ({@link #PROPERTY_COMBINE_POLICY_SUFFIX}) it is ignored! * This is reserved for combine policy tweaking. * * @param prefix for selecting the properties from which the list should be extracted * @param properties properties from which to extract from * @return parsed list or null if no element with prefixes exists */ public static List extractFromPropertiesAsList(String prefix, Properties properties) { TreeMap orderedMap = new TreeMap<>(); List rest = new ArrayList<>(); Enumeration names = properties.propertyNames(); String prefixP = prefix + "."; while (names.hasMoreElements()) { String key = (String) names.nextElement(); if (propMatchesPrefix(prefixP, key)) { String index = key.substring(prefixP.length()); if (PROPERTY_COMBINE_POLICY_SUFFIX.equals(index)) { continue; } String value = properties.getProperty(key); try { Integer nrIndex = Integer.parseInt(index); orderedMap.put(nrIndex, value); } catch (NumberFormatException exp) { rest.add(value); } } } List ret = new ArrayList<>(orderedMap.values()); ret.addAll(rest); return !ret.isEmpty() ? ret : null; } /** * Extract from a Maven property which is in the form ${name} the name. * * @param propName property name to extract * @return the pure name or null if this is not a property name */ public static String extractMavenPropertyName(String propName) { Matcher matcher = Pattern.compile(MAVEN_PROPERTY_REGEXP).matcher(propName); if (matcher.matches()) { return matcher.group(1); } else { return null; } } /** * Fix path on Windows machines, i.e. convert 'c:\...\' to '/c/..../' * * @param path path to fix * @return the fixed path */ public static String fixupPath(String path) { // Hack-fix for mounting on Windows where the ${projectDir} variable and other // contain backslashes and what not. Related to #188 Pattern pattern = Pattern.compile("^(?i)([A-Z]):(.*)$"); Matcher matcher = pattern.matcher(path); if (matcher.matches()) { String result = "/" + matcher.group(1).toLowerCase() + matcher.group(2); return result.replace("\\", "/"); } return path; } /** * Calculate the duration between now and the given time * *

Taken mostly from http://stackoverflow.com/a/5062810/207604 . Kudos to @dblevins * * @param start starting time (in milliseconds) * @return time in seconds */ public static String formatDurationTill(long start) { long duration = System.currentTimeMillis() - start; StringBuilder res = new StringBuilder(); TimeUnit current = HOURS; while (duration > 0) { long temp = current.convert(duration, MILLISECONDS); if (temp > 0) { duration -= current.toMillis(temp); res.append(temp).append(" ").append(current.name().toLowerCase()); if (temp < 2) res.deleteCharAt(res.length() - 1); res.append(COMMA_WHITESPACE); } if (current == SECONDS) { break; } current = TimeUnit.values()[current.ordinal() - 1]; } if (res.lastIndexOf(COMMA_WHITESPACE) < 0) { return duration + " " + MILLISECONDS.name().toLowerCase(); } res.deleteCharAt(res.length() - 2); int i = res.lastIndexOf(COMMA_WHITESPACE); if (i > 0) { res.deleteCharAt(i); res.insert(i, " and"); } return res.toString(); } // ====================================================================================================== private static boolean propMatchesPrefix(String prefix, String key) { return key.startsWith(prefix) && key.length() >= prefix.length(); } /** * Return the first non-null registry given. Use the env var DOCKER_REGISTRY as final fallback * * @param checkFirst list of registries to check * @return registry found or null if none. */ public static String firstRegistryOf(String... checkFirst) { for (String registry : checkFirst) { if (registry != null) { return registry; } } // Check environment as last resort return System.getenv("DOCKER_REGISTRY"); } // sometimes registries might be specified with https? schema, sometimes not public static String ensureRegistryHttpUrl(String registry) { if (registry.toLowerCase().startsWith("http")) { return registry; } // Default to https:// schema return "https://" + registry; } public static File prepareAbsoluteOutputDirPath(String outputDirectory, String projectBaseDir, String dir, String path) { return prepareAbsolutePath(projectBaseDir, new File(outputDirectory, dir).toString(), path); } public static File prepareAbsoluteSourceDirPath(String sourceDirectory, String projectBaseDir, String path) { return prepareAbsolutePath(projectBaseDir, sourceDirectory, path); } private static File prepareAbsolutePath(String projectBaseDir, String directory, String path) { File file = new File(path); if (file.isAbsolute()) { return file; } return new File(new File(projectBaseDir, directory), path); } /** * Create a timestamp file holding time in epoch seconds. * * @param tsFile the File to store the timestamp in. * @param buildDate the Date of the timestamp. * @throws IOException if the timestamp cannot be created. */ public static void storeTimestamp(File tsFile, Date buildDate) throws IOException { try { Files.deleteIfExists(tsFile.toPath()); final File dir = tsFile.getParentFile(); if (!dir.exists() && !dir.mkdirs()) { throw new IOException("Cannot create directory " + dir); } Files.write(tsFile.toPath(), Long.toString(buildDate.getTime()).getBytes(StandardCharsets.US_ASCII)); } catch (IOException e) { throw new IOException("Cannot create " + tsFile + " for storing time " + buildDate.getTime(), e); } } public static Date loadTimestamp(File tsFile) throws IOException { try { if (tsFile.exists()) { final String ts = new String(Files.readAllBytes(tsFile.toPath()), StandardCharsets.US_ASCII); return new Date(Long.parseLong(ts)); } else { return null; } } catch (IOException e) { throw new IOException("Cannot read timestamp " + tsFile, e); } } public static boolean isWindows() { return System.getProperty("os.name").toLowerCase().contains("windows"); } public static String getEnvVarOrSystemProperty(String varName, String defaultValue) { return getEnvVarOrSystemProperty(varName, varName, defaultValue); } public static String getEnvVarOrSystemProperty(String envVarName, String systemProperty, String defaultValue) { String ret = System.getenv(envVarName); if (StringUtils.isNotBlank(ret)){ return ret; } return System.getProperty(systemProperty, defaultValue); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy