1
+ using System ;
2
+ using System . IO ;
3
+ using System . Linq ;
4
+ using Amazon . Lambda . Annotations . SourceGenerator . FileIO ;
5
+ using Newtonsoft . Json ;
6
+ using Newtonsoft . Json . Linq ;
7
+
8
+ namespace Amazon . Lambda . Annotations . SourceGenerator
9
+ {
10
+ /// <summary>
11
+ /// This class contains utility methods to determine the .NET project's root directory and resolve the AWS serverless template file path.
12
+ /// </summary>
13
+ public class CloudFormationTemplateHandler
14
+ {
15
+ private const string DEFAULT_CONFIG_FILE_NAME = "aws-lambda-tools-defaults.json" ;
16
+ private const string DEFAULT_SERVERLESS_TEMPLATE_NAME = "serverless.template" ;
17
+
18
+ private readonly IFileManager _fileManager ;
19
+ private readonly IDirectoryManager _directoryManager ;
20
+
21
+ public CloudFormationTemplateHandler ( IFileManager fileManager , IDirectoryManager directoryManager )
22
+ {
23
+ _fileManager = fileManager ;
24
+ _directoryManager = directoryManager ;
25
+ }
26
+
27
+ /// <summary>
28
+ /// This method takes any file path in the customer's .NET project and resolves the project root directory.
29
+ /// The root directory is the folder that contains the .csproj file.
30
+ /// </summary>
31
+ /// <returns>The .NET project root directory path</returns>
32
+ public string DetermineProjectRootDirectory ( string sourceFilePath )
33
+ {
34
+ if ( ! _fileManager . Exists ( sourceFilePath ) )
35
+ return string . Empty ;
36
+
37
+ var directoryPath = _directoryManager . GetDirectoryName ( sourceFilePath ) ;
38
+ while ( ! string . IsNullOrEmpty ( directoryPath ) )
39
+ {
40
+ if ( _directoryManager . GetFiles ( directoryPath , "*.csproj" ) . Length == 1 )
41
+ return directoryPath ;
42
+ directoryPath = _directoryManager . GetDirectoryName ( directoryPath ) ;
43
+ }
44
+
45
+ return string . Empty ;
46
+ }
47
+
48
+ /// <summary>
49
+ /// Determines the path to the AWS serverless template file.
50
+ /// If the file does not exist then an empty file is created before returning the path.
51
+ /// </summary>
52
+ public string FindTemplate ( string projectRootDirectory )
53
+ {
54
+ var templateAbsolutePath = DetermineTemplatePath ( projectRootDirectory ) ;
55
+
56
+ if ( ! _fileManager . Exists ( templateAbsolutePath ) )
57
+ _fileManager . Create ( templateAbsolutePath ) . Close ( ) ;
58
+
59
+ return templateAbsolutePath ;
60
+ }
61
+
62
+ /// <summary>
63
+ /// Checks if the AWS serverless template file exists.
64
+ /// </summary>
65
+ public bool DoesTemplateExist ( string projectRootDirectory )
66
+ {
67
+ var templateAbsolutePath = DetermineTemplatePath ( projectRootDirectory ) ;
68
+ return _fileManager . Exists ( templateAbsolutePath ) ;
69
+ }
70
+
71
+ /// <summary>
72
+ /// Determines the file format of the AWS serverless template.
73
+ /// If the template does not exist or if the template is empty, then by default <see cref="CloudFormationTemplateFormat.Json"/> is returned.
74
+ /// </summary>
75
+ public CloudFormationTemplateFormat DetermineTemplateFormat ( string templatePath )
76
+ {
77
+ if ( ! _fileManager . Exists ( templatePath ) )
78
+ {
79
+ return CloudFormationTemplateFormat . Json ;
80
+ }
81
+
82
+ var content = _fileManager . ReadAllText ( templatePath ) ;
83
+ content = content . Trim ( ) ;
84
+ if ( string . IsNullOrEmpty ( content ) )
85
+ {
86
+ return CloudFormationTemplateFormat . Json ;
87
+ }
88
+
89
+ return content [ 0 ] == '{' ? CloudFormationTemplateFormat . Json : CloudFormationTemplateFormat . Yaml ;
90
+ }
91
+
92
+ /// <summary>
93
+ /// This is a helper method to determine the path to the AWS serverless template file.
94
+ /// It will first look for <see cref="DEFAULT_CONFIG_FILE_NAME"/> inside the project root directory and will try to resolve the template file path from the `template` property.
95
+ /// If <see cref="DEFAULT_CONFIG_FILE_NAME"/> does not exist or if the 'template' property is not found, then default to projectRootDirectory/<see cref="DEFAULT_SERVERLESS_TEMPLATE_NAME"/>
96
+ /// </summary>
97
+ private string DetermineTemplatePath ( string projectRootDirectory )
98
+ {
99
+ if ( ! _directoryManager . Exists ( projectRootDirectory ) )
100
+ throw new DirectoryNotFoundException ( "Failed to find the project root directory" ) ;
101
+
102
+ var templateAbsolutePath = string . Empty ;
103
+
104
+ var defaultConfigFile = _directoryManager . GetFiles ( projectRootDirectory , DEFAULT_CONFIG_FILE_NAME , SearchOption . AllDirectories )
105
+ . FirstOrDefault ( ) ;
106
+
107
+ if ( _fileManager . Exists ( defaultConfigFile ) )
108
+ // the templateAbsolutePath will be empty if the template property is not found in the default config file
109
+ templateAbsolutePath = GetTemplatePathFromDefaultConfigFile ( defaultConfigFile ) ;
110
+
111
+ // if the default config file does not exist or if the template property is not found in the default config file
112
+ // set the template path inside the project root directory.
113
+ if ( string . IsNullOrEmpty ( templateAbsolutePath ) )
114
+ templateAbsolutePath = Path . Combine ( projectRootDirectory , DEFAULT_SERVERLESS_TEMPLATE_NAME ) ;
115
+
116
+ return templateAbsolutePath ;
117
+ }
118
+ /// <summary>
119
+ /// This method parses the default config file and tries to resolve the serverless template path from the 'template' property.
120
+ /// </summary>
121
+ private string GetTemplatePathFromDefaultConfigFile ( string defaultConfigFile )
122
+ {
123
+ JToken rootToken ;
124
+ try
125
+ {
126
+ rootToken = JObject . Parse ( _fileManager . ReadAllText ( defaultConfigFile ) ) ;
127
+ }
128
+ catch ( Exception )
129
+ {
130
+ return string . Empty ;
131
+ }
132
+
133
+ var templateRelativePath = rootToken [ "template" ] ? . ToObject < string > ( ) ;
134
+
135
+ if ( string . IsNullOrEmpty ( templateRelativePath ) )
136
+ return string . Empty ;
137
+
138
+ var templateAbsolutePath = Path . Combine ( _directoryManager . GetDirectoryName ( defaultConfigFile ) , templateRelativePath ) ;
139
+ return templateAbsolutePath ;
140
+ }
141
+ }
142
+ }
0 commit comments