org.sonarsource.scanner.cli.Conf Maven / Gradle / Ivy
The newest version!
/*
* SonarScanner CLI
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonarsource.scanner.cli;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonarsource.scanner.lib.EnvironmentConfig;
class Conf {
private static final Logger LOG = LoggerFactory.getLogger(Conf.class);
private static final String SCANNER_HOME = "scanner.home";
private static final String SCANNER_SETTINGS = "scanner.settings";
private static final String PROJECT_HOME = "project.home";
private static final String PROJECT_SETTINGS = "project.settings";
private static final String PROPERTY_MODULES = "sonar.modules";
private static final String PROPERTY_PROJECT_BASEDIR = "sonar.projectBaseDir";
private static final String PROPERTY_PROJECT_CONFIG_FILE = "sonar.projectConfigFile";
private static final String SONAR_PROJECT_PROPERTIES_FILENAME = "sonar-project.properties";
static final String PROPERTY_SONAR_HOST_URL = "sonar.host.url";
private static final String BOOTSTRAP_START_TIME = "sonar.scanner.bootstrapStartTime";
private final Cli cli;
private final Map env;
private final long startTimeMs;
Conf(Cli cli, Map env) {
this.cli = cli;
this.env = env;
this.startTimeMs = System.currentTimeMillis();
}
Properties properties() {
Properties result = new Properties();
result.putAll(loadGlobalProperties());
result.putAll(loadProjectProperties());
result.putAll(System.getProperties());
result.putAll(loadEnvironmentProperties());
result.putAll(cli.properties());
result = resolve(result);
// root project base directory must be present and be absolute
result.setProperty(PROPERTY_PROJECT_BASEDIR, getRootProjectBaseDir(result).toString());
result.remove(PROJECT_HOME);
result.setProperty(BOOTSTRAP_START_TIME, String.valueOf(startTimeMs));
return result;
}
private Properties resolve(Properties props) {
PropertyResolver resolver = new PropertyResolver(props, env);
return resolver.resolve();
}
private static Map loadEnvironmentProperties() {
return EnvironmentConfig.load();
}
private Properties loadGlobalProperties() {
Properties knownPropsAtThatPoint = new Properties();
knownPropsAtThatPoint.putAll(System.getProperties());
knownPropsAtThatPoint.putAll(loadEnvironmentProperties());
knownPropsAtThatPoint.putAll(cli.properties());
Path settingsFile = locatePropertiesFile(knownPropsAtThatPoint, SCANNER_HOME, "conf/sonar-scanner.properties",
SCANNER_SETTINGS);
if (settingsFile != null && Files.isRegularFile(settingsFile)) {
LOG.info("Scanner configuration file: {}", settingsFile);
return toProperties(settingsFile);
}
LOG.info("Scanner configuration file: NONE");
return new Properties();
}
private Properties loadProjectProperties() {
Properties rootProps = new Properties();
Properties knownPropsAtThatPoint = new Properties();
knownPropsAtThatPoint.putAll(System.getProperties());
knownPropsAtThatPoint.putAll(loadEnvironmentProperties());
knownPropsAtThatPoint.putAll(cli.properties());
Path defaultRootSettingsFile = getRootProjectBaseDir(knownPropsAtThatPoint).resolve(SONAR_PROJECT_PROPERTIES_FILENAME);
Path rootSettingsFile = locatePropertiesFile(defaultRootSettingsFile, knownPropsAtThatPoint, PROJECT_SETTINGS);
if (rootSettingsFile != null && Files.isRegularFile(rootSettingsFile)) {
LOG.info("Project root configuration file: {}", rootSettingsFile);
rootProps.putAll(toProperties(rootSettingsFile));
} else {
LOG.info("Project root configuration file: NONE");
}
Properties projectProps = new Properties();
// include already root base directory and eventually props loaded from
// root config file
projectProps.putAll(rootProps);
rootProps.putAll(knownPropsAtThatPoint);
rootProps.setProperty(PROPERTY_PROJECT_BASEDIR, getRootProjectBaseDir(rootProps).toString());
// projectProps will be overridden by any properties found in child
// project settings
loadModulesProperties(rootProps, projectProps, "");
return projectProps;
}
private static Path getRootProjectBaseDir(Properties cliProps) {
Path absoluteProjectHome;
if (cliProps.containsKey(PROJECT_HOME)) {
absoluteProjectHome = Paths.get(cliProps.getProperty(PROJECT_HOME)).toAbsolutePath();
} else {
// this should always be avoided, as it will resolve symbolic links
absoluteProjectHome = Paths.get("").toAbsolutePath();
}
if (!cliProps.containsKey(PROPERTY_PROJECT_BASEDIR)) {
return absoluteProjectHome;
}
return getAbsolutePath(cliProps.getProperty(PROPERTY_PROJECT_BASEDIR), absoluteProjectHome);
}
private void loadModulesProperties(Properties parentProps, Properties projectProps, String prefix) {
Path parentBaseDir = Paths.get(parentProps.getProperty(PROPERTY_PROJECT_BASEDIR));
if (parentProps.containsKey(PROPERTY_MODULES)) {
for (String module : getListFromProperty(parentProps, PROPERTY_MODULES)) {
Properties moduleProps = extractModuleProperties(module, parentProps);
// higher priority to child configuration files
loadModuleConfigFile(parentBaseDir, moduleProps, module);
// the child project may have children as well
loadModulesProperties(moduleProps, projectProps, prefix + module + ".");
// and finally add this child properties to global props
merge(projectProps, prefix, module, moduleProps);
}
}
}
private static void merge(Properties projectProps, String prefix, String module, Properties moduleProps) {
for (Map.Entry