using System;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using AggregateConfigBuildTask.FileHandlers;
using Microsoft.Build.Framework;
using Task = Microsoft.Build.Utilities.Task;
[assembly: InternalsVisibleTo("AggregateConfig.Tests.UnitTests")]
namespace AggregateConfigBuildTask
{
///
/// Represents a task that aggregates configuration files from a directory and outputs a merged file with optional modifications.
///
public class AggregateConfig : Task
{
private readonly IFileSystem fileSystem;
private ITaskLogger logger;
///
/// The directory path where input files are located. This property is required.
///
[Required]
public string InputDirectory { get; set; }
///
/// The type of input file type to be processed from . If not specified, the default type is used.
///
public string InputType { get; set; }
///
/// The output file path where the merged result will be saved. This property is required.
///
[Required]
public string OutputFile { get; set; }
///
/// The type of the output file type to be created from . This property is required.
///
[Required]
public string OutputType { get; set; }
///
/// Specifies whether the source property (i.e., the file name) should be added to each merged object.
///
public bool AddSourceProperty { get; set; }
///
/// An array of additional properties that can be included in the output. These are user-specified key-value pairs.
///
public ITaskItem[] AdditionalProperties { get; set; }
///
/// Gets or sets whether quiet mode is enabled. When enabled, the logger will suppress non-critical messages.
///
public bool IsQuietMode
{
get
{
return logger is QuietTaskLogger;
}
set
{
logger = value && !(logger is QuietTaskLogger) ? new QuietTaskLogger(Log) : logger;
}
}
///
/// Initializes a new instance of the class with default file system and logger.
///
public AggregateConfig()
{
this.fileSystem = new FileSystem();
this.logger = new TaskLogger(Log);
}
internal AggregateConfig(IFileSystem fileSystem, ITaskLogger logger)
{
this.fileSystem = fileSystem;
this.logger = logger;
}
///
/// The entry point for the task.
///
/// A boolean that is true if processing was successful.
public override bool Execute()
{
try
{
EmitHeader();
InputDirectory = Path.GetFullPath(InputDirectory);
OutputFile = Path.GetFullPath(OutputFile);
if (!Enum.TryParse(OutputType, true, out FileType outputType) ||
!Enum.IsDefined(typeof(FileType), outputType))
{
logger.LogError(message: "Invalid FileType: {0}. Available options: {1}", OutputType, string.Join(", ", Enum.GetNames(typeof(FileType))));
return false;
}
FileType inputType = FileType.Yaml;
if (!string.IsNullOrEmpty(InputType) &&
(!Enum.TryParse(InputType, true, out inputType) || !Enum.IsDefined(typeof(FileType), inputType)))
{
logger.LogError(message: "Invalid FileType: {0}. Available options: {1}", InputType, string.Join(", ", Enum.GetNames(typeof(FileType))));
return false;
}
logger.LogMessage(MessageImportance.High, "Aggregating {0} to {1} in folder {2}", inputType, outputType, InputDirectory);
string directoryPath = Path.GetDirectoryName(OutputFile);
if (!fileSystem.DirectoryExists(directoryPath))
{
fileSystem.CreateDirectory(directoryPath);
}
var finalResult = ObjectManager.MergeFileObjects(InputDirectory, inputType, AddSourceProperty, fileSystem, logger).GetAwaiter().GetResult();
if (finalResult == null)
{
logger.LogError(message: "No input was found! Check the input directory.");
return false;
}
var additionalPropertiesDictionary = JsonHelper.ParseAdditionalProperties(AdditionalProperties);
finalResult = ObjectManager.InjectAdditionalProperties(finalResult, additionalPropertiesDictionary, logger).GetAwaiter().GetResult();
var writer = FileHandlerFactory.GetFileHandlerForType(fileSystem, outputType);
writer.WriteOutput(finalResult, OutputFile);
logger.LogMessage(MessageImportance.High, "Wrote aggregated configuration file to {0}", OutputFile);
return true;
}
catch (Exception ex)
{
logger.LogError(message: "An unknown exception occurred: {0}", ex.Message);
logger.LogErrorFromException(ex, true, true, null);
return false;
}
}
private void EmitHeader()
{
var assembly = Assembly.GetExecutingAssembly();
var informationalVersion = assembly
.GetCustomAttribute()?
.InformationalVersion;
logger.LogMessage(MessageImportance.Normal, $"AggregateConfig Version: {informationalVersion}");
}
}
}