nuget-server/src/jetbrains/buildServer/nuget/server/runner/install/PackagesInstallerRunnerDiscoverer.java (126 lines of code) (raw):
package jetbrains.buildServer.nuget.server.runner.install;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.StreamUtil;
import jetbrains.buildServer.nuget.common.PackagesConstants;
import jetbrains.buildServer.nuget.server.tool.NuGetServerToolProvider;
import jetbrains.buildServer.serverSide.BuildTypeSettings;
import jetbrains.buildServer.serverSide.SBuildRunnerDescriptor;
import jetbrains.buildServer.serverSide.discovery.BreadthFirstRunnerDiscoveryExtension;
import jetbrains.buildServer.serverSide.discovery.DiscoveredObject;
import jetbrains.buildServer.tools.ToolVersionReference;
import jetbrains.buildServer.util.*;
import jetbrains.buildServer.util.browser.Browser;
import jetbrains.buildServer.util.browser.Element;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Evgeniy.Koshkin
*/
public class PackagesInstallerRunnerDiscoverer extends BreadthFirstRunnerDiscoveryExtension {
private static final Logger LOG = Logger.getInstance(PackagesInstallerRunnerDiscoverer.class.getName());
private static final String PACKAGES_CONFIG = "packages.config";
private static final String NUGET_DIR_NAME = ".nuget";
private static final String SLN_FILE_EXTENSION = ".sln";
private static final Pattern PROJECT_PATH_PATTERN = Pattern.compile("^Project\\(.+\\)\\s*=\\s*\".+\"\\s*,\\s*\"(.+)\"\\s*,\\s*\".+\"\\s*$", Pattern.CASE_INSENSITIVE);
private static final Pattern PROJECT_NAME_PATTERN = Pattern.compile("^.+\\.(proj|csproj|vbproj)$", Pattern.CASE_INSENSITIVE);
@NotNull private final PackagesInstallerRunnerDefaults myDefaults;
public PackagesInstallerRunnerDiscoverer(@NotNull PackagesInstallerRunnerDefaults defaults) {
myDefaults = defaults;
}
@NotNull
@Override
protected List<DiscoveredObject> discoverRunnersInDirectory(@NotNull Element dir, @NotNull List<Element> filesAndDirs) {
List<String> foundSlns = new ArrayList<String>();
boolean nugetUsageFound = false;
for(Element item : filesAndDirs){
final String name = item.getName();
final boolean isLeaf = item.isLeaf();
if(isLeaf && name.endsWith(SLN_FILE_EXTENSION) && item.isContentAvailable()) {
foundSlns.add(item.getFullName());
if (!nugetUsageFound && hasPackages(item)) {
nugetUsageFound = true;
}
}
if(nugetUsageFound) continue;
nugetUsageFound = (isLeaf && name.equalsIgnoreCase(PACKAGES_CONFIG)) || (!isLeaf && name.equalsIgnoreCase(NUGET_DIR_NAME));
}
if (foundSlns.isEmpty() || !nugetUsageFound) return Collections.emptyList();
return CollectionsUtil.convertCollection(foundSlns, this::discover);
}
private boolean hasPackages(Element solutionFile) {
InputStream stream = null;
try {
stream = solutionFile.getInputStream();
final String text = StreamUtil.readText(stream);
for (String line : text.split("\\r?\\n")) {
final Matcher matcher = PROJECT_PATH_PATTERN.matcher(line);
if (!matcher.find()) {
continue;
}
final String projectFilePath = matcher.group(1);
if (!PROJECT_NAME_PATTERN.matcher(projectFilePath).find()) {
continue;
}
// Check packages.config file existence in the project file directory
final String packagesPath = FileUtil.normalizeRelativePath(solutionFile.getFullName() + "/../" + projectFilePath + "/../" + PACKAGES_CONFIG);
final Element packagesElement = solutionFile.getBrowser().getElement(packagesPath);
if (packagesElement != null && packagesElement.isContentAvailable()) {
return true;
}
// Check that project file contains PackageReferences
final String projectPath = FileUtil.normalizeRelativePath(solutionFile.getFullName() + "/../" + projectFilePath);
if (hasProjectReferences(solutionFile.getBrowser().getElement(projectPath))) {
return true;
}
}
} catch (IOException e) {
LOG.infoAndDebugDetails("Failed to read solution contents " + solutionFile.getFullName(), e);
} finally {
FileUtil.close(stream);
}
return false;
}
private boolean hasProjectReferences(Element projectFile) {
if (projectFile == null || !projectFile.isContentAvailable()) {
return false;
}
InputStream stream = null;
try {
stream = projectFile.getInputStream();
return StreamUtil.readText(stream).contains("PackageReference");
} catch (IOException e) {
LOG.infoAndDebugDetails("Failed to read project file contents " + projectFile.getFullName(), e);
} finally {
FileUtil.close(stream);
}
return false;
}
@NotNull
@Override
protected List<DiscoveredObject> postProcessDiscoveredObjects(@NotNull BuildTypeSettings settings, @NotNull Browser browser, @NotNull List<DiscoveredObject> discovered) {
if(discovered.isEmpty()) return discovered;
Set<String> configuredPaths = new HashSet<String>();
for (SBuildRunnerDescriptor r: settings.getBuildRunners()) {
if (r.getType().equals(PackagesConstants.INSTALL_RUN_TYPE)) {
String path = r.getParameters().get(PackagesConstants.SLN_PATH);
if (path != null) {
configuredPaths.add(FileUtil.toSystemIndependentName(path));
}
}
}
if (configuredPaths.isEmpty()) return discovered;
List<DiscoveredObject> res = new ArrayList<DiscoveredObject>();
for (DiscoveredObject obj: discovered) {
final String slnPath = obj.getParameters().get(PackagesConstants.SLN_PATH);
if (slnPath != null && configuredPaths.contains(FileUtil.toSystemIndependentName(slnPath))) continue;
res.add(obj);
}
return res;
}
private DiscoveredObject discover(String slnPath) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put(PackagesConstants.NUGET_PATH, ToolVersionReference.getDefaultToolReference(NuGetServerToolProvider.NUGET_TOOL_TYPE.getType()).getReference());
parameters.put(PackagesConstants.SLN_PATH, slnPath);
parameters.putAll(myDefaults.getRunnerProperties());
return new DiscoveredObject(PackagesConstants.INSTALL_RUN_TYPE, parameters);
}
}