// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using AWS.Deploy.Common.IO; using Newtonsoft.Json; namespace AWS.Deploy.Common.DeploymentManifest { public interface IDeploymentManifestEngine { Task UpdateDeploymentManifestFile(string saveCdkDirectoryFullPath, string targetApplicationFullPath); Task> GetRecipeDefinitionPaths(string targetApplicationFullPath); } /// /// This class contains the helper methods to update the deployment manifest file /// that keeps track of the save CDK deployment projects. /// public class DeploymentManifestEngine : IDeploymentManifestEngine { private readonly IDirectoryManager _directoryManager; private readonly IFileManager _fileManager; private const string DEPLOYMENT_MANIFEST_FILE_NAME = "aws-deployments.json"; public DeploymentManifestEngine(IDirectoryManager directoryManager, IFileManager fileManager) { _directoryManager = directoryManager; _fileManager = fileManager; } /// /// This method updates the deployment manifest json file by adding the directory path at which the CDK deployment project is saved. /// If the manifest file does not exists then a new file is generated. /// The absolute path to the directory at which the CDK deployment project is saved /// The absolute path to the target application csproj or fsproj file. /// Thrown if an error occured while trying to update the deployment manifest file. /// /// public async Task UpdateDeploymentManifestFile(string saveCdkDirectoryFullPath, string targetApplicationFullPath) { try { if (!_directoryManager.Exists(saveCdkDirectoryFullPath)) return; var deploymentManifestFilePath = GetDeploymentManifestFilePath(targetApplicationFullPath); var targetApplicationDirectoryPath = _directoryManager.GetDirectoryInfo(targetApplicationFullPath).Parent?.FullName ?? string.Empty; var saveCdkDirectoryRelativePath = _directoryManager.GetRelativePath(targetApplicationDirectoryPath, saveCdkDirectoryFullPath); DeploymentManifestModel deploymentManifestModel; if (_fileManager.Exists(deploymentManifestFilePath)) { deploymentManifestModel = await ReadManifestFile(deploymentManifestFilePath); if (deploymentManifestModel.DeploymentProjects == null) { deploymentManifestModel.DeploymentProjects = new List { new DeploymentManifestEntry(saveCdkDirectoryRelativePath) }; } else { deploymentManifestModel.DeploymentProjects.Add(new DeploymentManifestEntry(saveCdkDirectoryRelativePath)); } } else { var deploymentManifestEntries = new List { new DeploymentManifestEntry(saveCdkDirectoryRelativePath) }; deploymentManifestModel = new DeploymentManifestModel(deploymentManifestEntries); } var manifestFileJsonString = SerializeManifestModel(deploymentManifestModel); await _fileManager.WriteAllTextAsync(deploymentManifestFilePath, manifestFileJsonString); } catch (Exception ex) { throw new FailedToUpdateDeploymentManifestFileException(DeployToolErrorCode.DeploymentManifestUpdateFailed, $"Failed to update the deployment manifest file " + $"for the deployment project stored at '{saveCdkDirectoryFullPath}'", ex); } } /// /// This method deserializes the deployment-manifest file and returns a list of absolute paths of directories at which different CDK /// deployment projects are stored. The custom recipe snapshots are stored in this directory. /// The absolute path to the target application csproj or fsproj file /// /// A list containing absolute directory paths for CDK deployment projects. public async Task> GetRecipeDefinitionPaths(string targetApplicationFullPath) { var recipeDefinitionPaths = new List(); var deploymentManifestFilePath = GetDeploymentManifestFilePath(targetApplicationFullPath); var targetApplicationDirectoryPath = _directoryManager.GetDirectoryInfo(targetApplicationFullPath).Parent?.FullName ?? string.Empty; if (_fileManager.Exists(deploymentManifestFilePath)) { var deploymentManifestModel = await ReadManifestFile(deploymentManifestFilePath); if (deploymentManifestModel.DeploymentProjects == null) return recipeDefinitionPaths; foreach (var entry in deploymentManifestModel.DeploymentProjects) { var saveCdkDirectoryRelativePath = entry.SaveCdkDirectoryRelativePath; if (string.IsNullOrEmpty(saveCdkDirectoryRelativePath)) continue; var saveCdkDirectoryAbsolutePath = _directoryManager.GetAbsolutePath(targetApplicationDirectoryPath, saveCdkDirectoryRelativePath); if (_directoryManager.Exists(saveCdkDirectoryAbsolutePath)) recipeDefinitionPaths.Add(saveCdkDirectoryAbsolutePath); } } return recipeDefinitionPaths; } /// /// This method parses the deployment-manifest file into a /// /// The path to the deployment-manifest file /// An instance of private async Task ReadManifestFile(string filePath) { var manifestFilejsonString = await _fileManager.ReadAllTextAsync(filePath); return JsonConvert.DeserializeObject(manifestFilejsonString) ?? throw new FailedToDeserializeException(DeployToolErrorCode.InvalidDeploymentManifestModel, "The deployment manifest file is invalid."); } /// /// This method parses the into a string /// /// /// A formatted string representation of private string SerializeManifestModel(DeploymentManifestModel deploymentManifestModel) { return JsonConvert.SerializeObject(deploymentManifestModel, Formatting.Indented); } /// /// This method returns the path at which the deployment-manifest file will be stored. /// The absolute path to the target application csproj or fsproj file /// /// The path to the deployment-manifest file. private string GetDeploymentManifestFilePath(string targetApplicationFullPath) { var projectDirectoryFullPath = _directoryManager.GetDirectoryInfo(targetApplicationFullPath).Parent?.FullName ?? string.Empty; var deploymentManifestFileFullPath = Path.Combine(projectDirectoryFullPath, DEPLOYMENT_MANIFEST_FILE_NAME); return deploymentManifestFileFullPath; } } }