au.com.integradev.delphi.msbuild.DelphiProjectHelper Maven / Gradle / Ivy
The newest version!
/*
* Sonar Delphi Plugin
* Copyright (C) 2011 Sabre Airline Solutions and Fabricio Colombo
* Author(s):
* Przemyslaw Kociolek ([email protected])
* Michal Wojcik ([email protected])
* Fabricio Colombo ([email protected])
*
* 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 02
*/
package au.com.integradev.delphi.msbuild;
import static au.com.integradev.delphi.utils.DelphiUtils.inputFilesToPaths;
import static org.apache.commons.lang3.ArrayUtils.nullToEmpty;
import au.com.integradev.delphi.DelphiProperties;
import au.com.integradev.delphi.compiler.CompilerVersion;
import au.com.integradev.delphi.compiler.PredefinedConditionals;
import au.com.integradev.delphi.compiler.Toolchain;
import au.com.integradev.delphi.core.Delphi;
import au.com.integradev.delphi.enviroment.EnvironmentVariableProvider;
import au.com.integradev.delphi.utils.DelphiUtils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Iterables;
import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.config.Configuration;
import org.sonar.api.scanner.ScannerSide;
import org.sonarsource.api.sonarlint.SonarLintSide;
@ScannerSide
@SonarLintSide
public class DelphiProjectHelper {
private static final Logger LOG = LoggerFactory.getLogger(DelphiProjectHelper.class);
private final Configuration settings;
private final FileSystem fs;
private final EnvironmentVariableProvider environmentVariableProvider;
private final List projects;
private final Toolchain toolchain;
private final CompilerVersion compilerVersion;
private final List searchDirectories;
private final List debugSourceDirectories;
private final List referencedFiles;
private final Set conditionalDefines;
private final Set unitScopeNames;
private final Map unitAliases;
private boolean indexedProjects;
/**
* Constructor
*
* @param settings Project settings
* @param fs Sonar FileSystem
*/
public DelphiProjectHelper(
Configuration settings,
FileSystem fs,
EnvironmentVariableProvider environmentVariableProvider) {
this.settings = settings;
this.fs = fs;
this.environmentVariableProvider = environmentVariableProvider;
this.projects = new ArrayList<>();
this.toolchain = getToolchainFromSettings();
this.compilerVersion = getCompilerVersionFromSettings();
this.searchDirectories = getSearchDirectoriesFromSettings();
this.debugSourceDirectories = new ArrayList<>();
this.referencedFiles = new ArrayList<>();
this.conditionalDefines = getPredefinedConditionalDefines();
this.unitScopeNames = getSetFromSettings(DelphiProperties.UNIT_SCOPE_NAMES_KEY);
this.unitAliases = getUnitAliasesFromSettings();
}
private Set getSetFromSettings(String key) {
return Arrays.stream(nullToEmpty(settings.getStringArray(key))).collect(Collectors.toSet());
}
private Toolchain getToolchainFromSettings() {
return EnumUtils.getEnumIgnoreCase(
Toolchain.class,
settings.get(DelphiProperties.COMPILER_TOOLCHAIN_KEY).orElse(null),
DelphiProperties.COMPILER_TOOLCHAIN_DEFAULT);
}
private CompilerVersion getCompilerVersionFromSettings() {
String versionSymbol =
settings
.get(DelphiProperties.COMPILER_VERSION_KEY)
.orElse(DelphiProperties.COMPILER_VERSION_DEFAULT.symbol());
try {
return CompilerVersion.fromVersionSymbol(versionSymbol);
} catch (CompilerVersion.FormatException e) {
LOG.warn(
"Defaulting to compiler version \"{}\" because the provided one was invalid: \"{}\"",
DelphiProperties.COMPILER_VERSION_DEFAULT,
versionSymbol);
LOG.debug("Exception: ", e);
return DelphiProperties.COMPILER_VERSION_DEFAULT;
}
}
private List getSearchDirectoriesFromSettings() {
String[] searchDirectoriesSetting =
nullToEmpty(settings.getStringArray(DelphiProperties.SEARCH_PATH_KEY));
List result = new ArrayList<>();
for (String path : searchDirectoriesSetting) {
if (StringUtils.isBlank(path)) {
continue;
}
File included = DelphiUtils.resolveAbsolutePath(fs.baseDir().getAbsolutePath(), path.trim());
if (!included.exists()) {
LOG.warn("{} {}", "Search path directory does not exist: ", included.getAbsolutePath());
} else if (!included.isDirectory()) {
LOG.warn("{} {}", "Search path item is not a directory: ", included.getAbsolutePath());
} else {
result.add(included.toPath());
}
}
return result;
}
private Map getUnitAliasesFromSettings() {
String[] aliases = nullToEmpty(settings.getStringArray(DelphiProperties.UNIT_ALIASES_KEY));
Map result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Arrays.stream(aliases)
.forEach(
item -> {
if (StringUtils.countMatches(item, '=') != 1) {
LOG.warn("Invalid unit alias syntax: '{}'", item);
return;
}
int equalIndex = item.indexOf('=');
String unitAlias = item.substring(0, equalIndex).trim();
String unitName = item.substring(equalIndex + 1).trim();
result.put(unitAlias, unitName);
});
return result;
}
private Set getPredefinedConditionalDefines() {
return PredefinedConditionals.getConditionalDefines(toolchain, compilerVersion);
}
private void indexProjects() {
if (indexedProjects) {
return;
}
FilePredicates p = fs.predicates();
Iterable dprojFiles = fs.inputFiles(p.and(p.hasExtension("dproj")));
Iterable gprojFiles = fs.inputFiles(p.and(p.hasExtension("groupproj")));
if (dprojFiles == null) {
dprojFiles = Collections.emptyList();
}
if (gprojFiles == null) {
gprojFiles = Collections.emptyList();
}
LOG.info(
"Indexing {} dproj file(s) and {} groupproj file(s)...",
Iterables.size(dprojFiles),
Iterables.size(gprojFiles));
inputFilesToPaths(dprojFiles).forEach(this::indexProject);
inputFilesToPaths(gprojFiles).forEach(this::indexProjectGroup);
for (DelphiProject project : projects) {
searchDirectories.addAll(project.getSearchDirectories());
debugSourceDirectories.addAll(project.getDebugSourceDirectories());
conditionalDefines.addAll(project.getConditionalDefines());
referencedFiles.addAll(project.getSourceFiles());
unitScopeNames.addAll(project.getUnitScopeNames());
unitAliases.putAll(project.getUnitAliases());
}
conditionalDefines.addAll(getSetFromSettings(DelphiProperties.CONDITIONAL_DEFINES_KEY));
conditionalDefines.removeAll(getSetFromSettings(DelphiProperties.CONDITIONAL_UNDEFINES_KEY));
indexedProjects = true;
}
@VisibleForTesting
Path environmentProjPath() {
Path bdsPath = installationPath();
if (bdsPath.getNameCount() < 3) {
return null;
}
String appdata = environmentVariableProvider.getenv("APPDATA");
if (appdata == null) {
return null;
}
Path appdataPath = Path.of(appdata);
String companyName = bdsPath.getParent().getParent().getFileName().toString();
String productVersion = bdsPath.getFileName().toString();
return appdataPath
.resolve(companyName)
.resolve("BDS")
.resolve(productVersion)
.resolve("environment.proj");
}
private void indexProject(Path dprojFile) {
DelphiProjectParser parser =
new DelphiProjectParser(dprojFile, environmentVariableProvider, environmentProjPath());
DelphiProject newProject = parser.parse();
projects.add(newProject);
}
private void indexProjectGroup(Path projectGroup) {
DelphiProjectGroupParser parser =
new DelphiProjectGroupParser(
projectGroup, environmentVariableProvider, environmentProjPath());
projects.addAll(parser.parse());
}
/**
* Returns a path to the Delphi installation folder, as specified in settings
*
* @return Path to the installation folder
*/
public Path installationPath() {
String path =
settings
.get(DelphiProperties.INSTALLATION_PATH_KEY)
.orElseThrow(
() ->
new RuntimeException(
"Property '"
+ DelphiProperties.INSTALLATION_PATH_KEY
+ "' must be supplied."));
return Path.of(path);
}
/**
* Returns a path to the Delphi standard library, based on the installation path specified in
* settings.
*
* @return Path to standard library
*/
public Path standardLibraryPath() {
return installationPath().resolve("source");
}
/**
* Get the compiler version
*
* @return the compiler version
*/
public CompilerVersion getCompilerVersion() {
return compilerVersion;
}
/**
* Get the compiler toolchain
*
* @return the compiler toolchain
*/
public Toolchain getToolchain() {
return toolchain;
}
/**
* Gets the search directories specified in settings and project files
*
* @return List of search path directories
*/
public List getSearchDirectories() {
indexProjects();
return searchDirectories;
}
/**
* Gets the debug source directories specified in project files
*
* @return List of debug source directorie
*/
public List getDebugSourceDirectories() {
indexProjects();
return debugSourceDirectories;
}
/**
* Gets the set of conditional defines specified in settings and project files
*
* @return set of conditional defines
*/
public Set getConditionalDefines() {
indexProjects();
return conditionalDefines;
}
/**
* Gets the set of unit scope names specified in settings and project files
*
* @return set of unit scope names
*/
public Set getUnitScopeNames() {
indexProjects();
return unitScopeNames;
}
/**
* Gets the map of unit aliases specified in settings and project files
*
* @return map of unit aliases
*/
public Map getUnitAliases() {
indexProjects();
return unitAliases;
}
public List getReferencedFiles() {
indexProjects();
return referencedFiles;
}
public Iterable inputFiles() {
FilePredicates p = fs.predicates();
return fs.inputFiles(p.and(p.hasLanguage(Delphi.KEY)));
}
public boolean shouldExecuteOnProject() {
return fs.hasFiles(fs.predicates().hasLanguage(Delphi.KEY));
}
public InputFile getFile(String path) {
return fs.inputFile(fs.predicates().hasURI(Paths.get(path).toUri()));
}
public InputFile getFileFromBasename(String basename) {
return fs.inputFile(fs.predicates().hasFilename(basename));
}
public String encoding() {
return fs != null ? fs.encoding().name() : Charset.defaultCharset().name();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy