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

au.com.integradev.delphi.msbuild.DelphiProjectParser 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 au.com.integradev.delphi.enviroment.EnvironmentVariableProvider;
import au.com.integradev.delphi.utils.DelphiUtils;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class DelphiProjectParser {
  private static final Logger LOG = LoggerFactory.getLogger(DelphiProjectParser.class);

  private final Path dproj;
  private final EnvironmentVariableProvider environmentVariableProvider;
  private final Path environmentProj;

  public DelphiProjectParser(
      Path dproj, EnvironmentVariableProvider environmentVariableProvider, Path environmentProj) {
    this.dproj = dproj;
    this.environmentVariableProvider = environmentVariableProvider;
    this.environmentProj = environmentProj;
  }

  public DelphiProject parse() {
    var parser = new DelphiMSBuildParser(dproj, environmentVariableProvider, environmentProj);
    DelphiMSBuildParser.Result result = parser.parse();

    Path dprojDirectory = dproj.getParent();

    DelphiProjectImpl project = new DelphiProjectImpl();
    project.setDefinitions(createDefinitions(result.getProperties()));
    project.setUnitScopeNames(createUnitScopeNames(result.getProperties()));
    project.setSearchDirectories(createSearchDirectories(dprojDirectory, result.getProperties()));
    project.setDebugSourceDirectories(createDebugSourceDirectories(result.getProperties()));
    project.setUnitAliases(createUnitAliases(result.getProperties()));
    project.setSourceFiles(result.getSourceFiles());

    return project;
  }

  private static Set createDefinitions(ProjectProperties properties) {
    return Set.copyOf(propertyList(properties.get("DCC_Define")));
  }

  private static Set createUnitScopeNames(ProjectProperties properties) {
    return Set.copyOf(propertyList(properties.get("DCC_Namespace")));
  }

  private List createSearchDirectories(Path dprojDirectory, ProjectProperties properties) {
    /*
     We manually append the library paths here, even though it's not strictly correct to do so.

     CodeGear.Delphi.Targets appends the library paths to DCC_UnitSearchPath to create a new
     property called UnitSearchPath, which then gets passed through to the compiler.

     However, there are some good reasons not to just read the UnitSearchPath property:

     - It would tie us to an implementation detail of the MSBuild glue in CodeGear.Delphi.Targets.
     - If the UnitSearchPath property were ever renamed, we'd fall out of compatibility.
     - Relying on CodeGear.Delphi.Targets details would require us to mock it up in testing.
    */

    List allPaths = new ArrayList<>();

    allPaths.add(dprojDirectory);
    allPaths.addAll(createPathList(properties, "DCC_UnitSearchPath"));
    allPaths.addAll(createPathList(properties, "DelphiLibraryPath", false));
    allPaths.addAll(createPathList(properties, "DelphiTranslatedLibraryPath", false));

    return Collections.unmodifiableList(allPaths);
  }

  private List createDebugSourceDirectories(ProjectProperties properties) {
    return createPathList(properties, "Debugger_DebugSourcePath");
  }

  private List createPathList(ProjectProperties properties, String propertyName) {
    return createPathList(properties, propertyName, true);
  }

  private List createPathList(
      ProjectProperties properties, String propertyName, boolean emitWarnings) {
    List result = new ArrayList<>();
    propertyList(properties.get(propertyName))
        .forEach(
            pathString -> {
              Path path = resolveDirectory(pathString);
              if (path != null) {
                result.add(path);
              } else if (emitWarnings) {
                LOG.warn("Invalid {} directory: {}", propertyName, pathString);
              }
            });
    return Collections.unmodifiableList(result);
  }

  @Nullable
  private Path resolveDirectory(String pathString) {
    try {
      pathString = DelphiUtils.normalizeFileName(pathString);
      Path path = DelphiUtils.resolvePathFromBaseDir(evaluationDirectory(), Path.of(pathString));
      if (Files.isDirectory(path)) {
        return path;
      }
    } catch (InvalidPathException e) {
      LOG.debug("Invalid path string", e);
    }
    return null;
  }

  private static Map createUnitAliases(ProjectProperties properties) {
    Map result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    propertyList(properties.get("DCC_UnitAlias"))
        .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);
              String unitName = item.substring(equalIndex + 1);
              result.put(unitAlias, unitName);
            });
    return Collections.unmodifiableMap(result);
  }

  private static List propertyList(String value) {
    if (value == null) {
      return Collections.emptyList();
    }
    return Splitter.on(';').omitEmptyStrings().splitToList(value);
  }

  private Path evaluationDirectory() {
    return dproj.getParent();
  }

  private static class DelphiProjectImpl implements DelphiProject {
    private Set definitions = Collections.emptySet();
    private Set unitScopeNames = Collections.emptySet();
    private List sourceFiles = Collections.emptyList();
    private List searchDirectories = Collections.emptyList();
    private List debugSourceDirectories = Collections.emptyList();
    private Map unitAliases = Collections.emptyMap();

    private void setDefinitions(Set definitions) {
      this.definitions = ImmutableSortedSet.copyOf(String.CASE_INSENSITIVE_ORDER, definitions);
    }

    private void setUnitScopeNames(Set unitScopeNames) {
      this.unitScopeNames =
          ImmutableSortedSet.copyOf(String.CASE_INSENSITIVE_ORDER, unitScopeNames);
    }

    private void setSourceFiles(List sourceFiles) {
      this.sourceFiles = List.copyOf(sourceFiles);
    }

    private void setSearchDirectories(List searchDirectories) {
      this.searchDirectories = List.copyOf(searchDirectories);
    }

    private void setDebugSourceDirectories(List debugSourceDirectories) {
      this.debugSourceDirectories = List.copyOf(debugSourceDirectories);
    }

    private void setUnitAliases(Map unitAliases) {
      this.unitAliases = ImmutableSortedMap.copyOf(unitAliases, String.CASE_INSENSITIVE_ORDER);
    }

    @Override
    public Set getConditionalDefines() {
      return definitions;
    }

    @Override
    public Set getUnitScopeNames() {
      return unitScopeNames;
    }

    @Override
    public List getSourceFiles() {
      return sourceFiles;
    }

    @Override
    public List getSearchDirectories() {
      return searchDirectories;
    }

    @Override
    public List getDebugSourceDirectories() {
      return debugSourceDirectories;
    }

    @Override
    public Map getUnitAliases() {
      return unitAliases;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy