<commit_before>/*
 * CODENVY CONFIDENTIAL
 * __________________
 *
 *  [2012] - [2015] Codenvy, S.A.
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Codenvy S.A. and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Codenvy S.A.
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Codenvy S.A..
 */
package com.codenvy.im.managers;

import com.codenvy.im.artifacts.Artifact;
import com.codenvy.im.artifacts.ArtifactNotFoundException;
import com.codenvy.im.artifacts.CDECArtifact;
import com.codenvy.im.artifacts.InstallManagerArtifact;
import com.codenvy.im.utils.HttpTransport;
import com.codenvy.im.utils.Version;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalINIConfiguration;
import org.apache.commons.configuration.SubnodeConfiguration;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Named;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.codenvy.im.utils.Commons.combinePaths;
import static java.lang.String.format;
import static java.nio.file.Files.exists;
import static java.nio.file.Files.newInputStream;

/** @author <NAME> */
@Singleton
public class ConfigManager {
    private static final Pattern VARIABLE_TEMPLATE = Pattern.compile("\\$\\{([^\\}]*)\\}"); // ${...}

    private final HttpTransport transport;
    private final String        updateEndpoint;
    private final String        puppetBaseDir;
    private final Path          puppetConfFile;

    @Inject
    public ConfigManager(@Named("installation-manager.update_server_endpoint") String updateEndpoint,
                         @Named("puppet.base_dir") String puppetBaseDir,
                         HttpTransport transport) {
        this.transport = transport;
        this.updateEndpoint = updateEndpoint;
        this.puppetBaseDir = puppetBaseDir;
        this.puppetConfFile = Paths.get(puppetBaseDir, Config.PUPPET_CONF_FILE_NAME).toAbsolutePath();
    }

    /** Loads properties from the given file. */
    public Map<String, String> loadConfigProperties(Path confFile) throws IOException {
        if (!exists(confFile)) {
            throw new FileNotFoundException(format("Configuration file '%s' not found", confFile.toString()));
        }

        try (InputStream in = newInputStream(confFile)) {
            return doLoad(in);
        } catch (IOException e) {
            throw new ConfigException(format("Can't load properties: %s", e.getMessage()), e);
        }
    }

    /** Loads properties from the given file. */
    public Map<String, String> loadConfigProperties(String confFile) throws IOException {
        return loadConfigProperties(Paths.get(confFile));
    }

    /** Loads default properties. */
    public Map<String, String> loadCodenvyDefaultProperties(Version version, InstallType installType) throws IOException {
        Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"));

        String requestUrl = combinePaths(updateEndpoint, "/repository/public/download/codenvy-" +
                                                         (installType == InstallType.MULTI_SERVER ? "multi" : "single")
                                                         + "-server-properties/" + version);
        Path properties;
        try {
            properties = transport.download(requestUrl, tmpDir);
        } catch (IOException e) {
            throw new IOException("Can't download installation properties. " + e.getMessage(), e);
        }

        try (InputStream in = newInputStream(properties)) {
            return doLoad(in);
        } catch (IOException e) {
            throw new ConfigException(format("Can't load properties: %s", e.getMessage()), e);
        }
    }

    /**
     * Merges two bunches of the properties from current and new configurations.
     * As a rule method keeps the values of the old configuration except the {@link Config#VERSION} property
     * and cases where new default values came.
     *
     * @return the only properties are needed to be updated
     */
    public Map<String, String> merge(Version curVersion,
                                     Map<String, String> curProps,
                                     Map<String, String> newProps) throws IOException {

        InstallType installType = detectInstallationType();
        Map<String, String> curDefaultProps = loadCodenvyDefaultProperties(curVersion, installType);

        Map<String, String> props = new HashMap<>(curProps);

        for (Map.Entry<String, String> e : newProps.entrySet()) {
            String name = e.getKey();
            String newValue = e.getValue();

            // keep passwords

            if (!curProps.containsKey(name)) {
                props.put(name, newValue);
            } else if (name.contains("pass") || name.contains("pwd") || name.contains("client_id") || name.contains("secret")) {
                continue;
            } else if (curDefaultProps.containsKey(name) && curProps.get(name).equals(curDefaultProps.get(name))) {
                props.put(name, newValue);
            }
        }

        return props;
    }

    /**
     * Loads properties of the installed cdec artifact.
     * <p/>
     * The properties file has the follow format:
     * $property="value"
     * ...
     * <p/>
     * Finally method removes leading '$' for key name and quota characters for its value.
     */
    public Map<String, String> loadInstalledCodenvyProperties(InstallType installType) throws IOException {
        Map<String, String> properties = new HashMap<>();

        Iterator<Path> files = getCodenvyPropertiesFiles(installType);
        while (files.hasNext()) {
            Path propertiesFile = files.next();

            try (InputStream in = newInputStream(propertiesFile)) {
                Map<String, String> m = doLoad(in);

                for (Map.Entry<String, String> e : m.entrySet()) {
                    String key = e.getKey().trim();
                    if (key.startsWith("$")) {
                        key = key.substring(1); // removes '$'<commit_msg>Fix merging properties. Keep modified values<commit_after>/*
 * CODENVY CONFIDENTIAL
 * __________________
 *
 *  [2012] - [2015] Codenvy, S.A.
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Codenvy S.A. and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Codenvy S.A.
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Codenvy S.A..
 */
package com.codenvy.im.managers;

import com.codenvy.im.artifacts.Artifact;
import com.codenvy.im.artifacts.ArtifactNotFoundException;
import com.codenvy.im.artifacts.CDECArtifact;
import com.codenvy.im.artifacts.InstallManagerArtifact;
import com.codenvy.im.utils.HttpTransport;
import com.codenvy.im.utils.Version;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalINIConfiguration;
import org.apache.commons.configuration.SubnodeConfiguration;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Named;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.codenvy.im.utils.Commons.combinePaths;
import static java.lang.String.format;
import static java.nio.file.Files.exists;
import static java.nio.file.Files.newInputStream;

/** @author <NAME> */
@Singleton
public class ConfigManager {
    private static final Pattern VARIABLE_TEMPLATE = Pattern.compile("\\$\\{([^\\}]*)\\}"); // ${...}

    private final HttpTransport transport;
    private final String        updateEndpoint;
    private final String        puppetBaseDir;
    private final Path          puppetConfFile;

    @Inject
    public ConfigManager(@Named("installation-manager.update_server_endpoint") String updateEndpoint,
                         @Named("puppet.base_dir") String puppetBaseDir,
                         HttpTransport transport) {
        this.transport = transport;
        this.updateEndpoint = updateEndpoint;
        this.puppetBaseDir = puppetBaseDir;
        this.puppetConfFile = Paths.get(puppetBaseDir, Config.PUPPET_CONF_FILE_NAME).toAbsolutePath();
    }

    /** Loads properties from the given file. */
    public Map<String, String> loadConfigProperties(Path confFile) throws IOException {
        if (!exists(confFile)) {
            throw new FileNotFoundException(format("Configuration file '%s' not found", confFile.toString()));
        }

        try (InputStream in = newInputStream(confFile)) {
            return doLoad(in);
        } catch (IOException e) {
            throw new ConfigException(format("Can't load properties: %s", e.getMessage()), e);
        }
    }

    /** Loads properties from the given file. */
    public Map<String, String> loadConfigProperties(String confFile) throws IOException {
        return loadConfigProperties(Paths.get(confFile));
    }

    /** Loads default properties. */
    public Map<String, String> loadCodenvyDefaultProperties(Version version, InstallType installType) throws IOException {
        Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"));

        String requestUrl = combinePaths(updateEndpoint, "/repository/public/download/codenvy-" +
                                                         (installType == InstallType.MULTI_SERVER ? "multi" : "single")
                                                         + "-server-properties/" + version);
        Path properties;
        try {
            properties = transport.download(requestUrl, tmpDir);
        } catch (IOException e) {
            throw new IOException("Can't download installation properties. " + e.getMessage(), e);
        }

        try (InputStream in = newInputStream(properties)) {
            return doLoad(in);
        } catch (IOException e) {
            throw new ConfigException(format("Can't load properties: %s", e.getMessage()), e);
        }
    }

    /**
     * Merges two bunches of the properties from current and new configurations.
     */
    public Map<String, String> merge(Version curVersion,
                                     Map<String, String> curProps,
                                     Map<String, String> newProps) throws IOException {

        InstallType installType = detectInstallationType();
        Map<String, String> curDefaultProps = loadCodenvyDefaultProperties(curVersion, installType);

        Map<String, String> props = new HashMap<>(newProps);

        for (Map.Entry<String, String> e : curProps.entrySet()) {
            String name = e.getKey();
            String value = e.getValue();

            if (props.containsKey(name)) {
                if (curDefaultProps.containsKey(name) && !value.equals(curDefaultProps.get(name))) {
                    props.put(name, value);
                }
            }
        }

        return props;
    }

    /**
     * Loads properties of the installed cdec artifact.
     * <p/>
     * The properties file has the follow format:
     * $property="value"
     * ...
     * <p/>
     * Finally method removes leading '$' for key name and quota characters for its value.
     */
    public Map<String, String> loadInstalledCodenvyProperties(InstallType installType) throws IOException {
        Map<String, String> properties = new HashMap<>();

        Iterator<Path> files = getCodenvyPropertiesFiles(installType);
        while (files.hasNext()) {
            Path propertiesFile = files.next();

            try (InputStream in = newInputStream(propertiesFile)) {
                Map<String, String> m = doLoad(in);

                for (Map.Entry<String, String> e : m.entrySet()) {
                    String key = e.getKey().trim();
                    if (key.startsWith("$")) {
                        key = key.substring(1); // removes '$'
{'fraction_non_alphanumeric': 0.10482860302248434, 'fraction_numerical': 0.0013269443420567638, 'mean_word_length': 2.7444107093568864, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7253396', 'n_tokens_mistral': 3625, 'n_tokens_neox': 3523, 'n_words': 953}