using CTA.Rules.Models;
using CTA.Rules.PortCore;
using Microsoft.Extensions.Logging;
using PortingAssistant.Client.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace PortingAssistant.Client.PortingProjectFile
{
///
/// Creates a handler to port projects
///
public class PortingProjectFileHandler : IPortingProjectFileHandler
{
private readonly ILogger _logger;
///
/// Creates an instance of a PortingProjectFileHandler
///
/// An ILogger object
public PortingProjectFileHandler(ILogger logger)
{
_logger = logger;
}
///
/// Ports a list of projects
///
/// List of projects paths
/// Path to solution file
/// Target framework to be used when porting
/// List of key/value pairs where key is package and value is version number
/// A PortingProjectFileResult object, representing the result of the porting operation
///
public List ApplyProjectChanges(
List projects,
string solutionPath,
string targetFramework,
Dictionary> upgradeVersions)
{
return ApplyProjectChanges(projects, solutionPath, targetFramework, true, upgradeVersions);
}
///
/// Ports a list of projects
///
/// List of project paths
/// Path to solution file
/// Target framework to be used when porting
/// List of key/value pairs where key is package and value is version number
/// A PortingProjectFileResult object, representing the result of the porting operation
///
public List ApplyProjectChanges(
List projects,
string solutionPath,
string targetFramework,
bool includeCodeFix,
Dictionary> upgradeVersions, VisualStudioVersion? visualStudioVersion = null)
{
var results = new List();
var projectFilesNotFound = projects.Where((p) => !File.Exists(p.ProjectFilePath)).ToList();
projectFilesNotFound.ForEach((p) => results.Add(new PortingResult
{
Message = "File not found.",
ProjectFile = p.ProjectFilePath,
ProjectName = Path.GetFileNameWithoutExtension(p.ProjectFilePath),
Success = false
}));
projects = projects.Where((p) => File.Exists(p.ProjectFilePath)).ToList();
var (projectsWithAccess, noAccessPortingResults) = VerifyFileAccess(projects);
results.AddRange(noAccessPortingResults);
projects = projectsWithAccess;
_logger.LogInformation("Applying porting changes to {0}", projects.Select(p => p.ProjectFilePath).ToList());
List configs = new List();
projects.Where(p => !p.IsBuildFailed).ToList().ForEach((proj) =>
{
var upgradePackages = upgradeVersions
.Where(p => proj.PackageReferences
.Exists(package => package.PackageId == p.Key))
.ToDictionary(t => t.Key, t => t.Value);
configs.Add(new PortCoreConfiguration()
{
ProjectPath = proj.ProjectFilePath,
UseDefaultRules = true,
PackageReferences = upgradePackages,
TargetVersions = new List { targetFramework },
PortCode = includeCodeFix
});
});
try
{
SolutionPort solutionPort = new SolutionPort(solutionPath, configs, _logger, visualStudioVersion: visualStudioVersion?.ToString());
solutionPort.Run();
}
catch (Exception ex)
{
_logger.LogError($"Failed to port projects {projects.Select(p => p.ProjectFilePath).ToList()} with error: {ex}");
configs.ForEach(config =>
{
if (!projectFilesNotFound.Exists(p => p.ProjectFilePath == config.ProjectPath))
{
results.Add(new PortingResult
{
Message = $"porting project with error {ex.Message}",
Success = false,
ProjectFile = config.ProjectPath,
ProjectName = Path.GetFileNameWithoutExtension(config.ProjectPath)
});
}
});
return results;
}
//TODO Return result from solution run
projects.Where(p => !projectFilesNotFound.Exists(proj => proj.ProjectFilePath == p.ProjectFilePath) && !p.IsBuildFailed)
.ToList().ForEach((p) => results.Add(new PortingResult
{
ProjectFile = p.ProjectFilePath,
ProjectName = Path.GetFileNameWithoutExtension(p.ProjectFilePath),
Success = true
}));
_logger.LogInformation("Completed porting changes to {0}", projects.Select(p => p.ProjectFilePath).ToList());
return results;
}
///
/// Checks projects to make sure we have access to the project file and at least one csharp file
///
/// List of projects to check for write access
///
/// Valid projects with access, Porting result for projects without access
///
private (List, List) VerifyFileAccess(List projects)
{
var noAccessPortingResults = new List();
var projectsWithAccess = new List();
foreach (ProjectDetails project in projects)
{
if (Common.Utils.FileSystemAccess.CheckWriteAccessForProject(project.ProjectFilePath))
{
projectsWithAccess.Add(project);
}
else
{
noAccessPortingResults.Add(new PortingResult
{
Success = false,
ProjectFile = project.ProjectFilePath,
ProjectName = project.ProjectName,
Message = $"Application does not have write access to project: {project.ProjectName}",
Exception = new UnauthorizedAccessException()
});
}
}
return (projectsWithAccess, noAccessPortingResults);
}
}
}