Skip to content

Commit dfe3107

Browse files
authored
JsonPropertyPostAction: allow to create file and path (#41959)
2 parents 17304ec + 3b4ce6b commit dfe3107

17 files changed

+426
-61
lines changed

src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.Designer.cs

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/Microsoft.TemplateEngine.Cli/LocalizableStrings.resx

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@
307307
</data>
308308
<data name="TemplatePackageCoordinator_VulnerabilitySeverity_Moderate" xml:space="preserve">
309309
<value>Moderate</value>
310-
<comment>represents nuget api severity of level 1.</comment>
310+
<comment>represents nuget api severity of level 1.</comment>
311311
</data>
312312
<data name="TemplatePackageCoordinator_VulnerabilitySeverity_High" xml:space="preserve">
313313
<value>High</value>
@@ -859,67 +859,64 @@ The header is followed by the list of parameters and their errors (might be seve
859859
<data name="Generic_CommandHints_List" xml:space="preserve">
860860
<value>To list installed templates, run:</value>
861861
</data>
862-
<data name="DetailsCommand_Argument_PackageIdentifier">
862+
<data name="DetailsCommand_Argument_PackageIdentifier" xml:space="preserve">
863863
<value>Package identifier</value>
864864
</data>
865-
<data name="DetailsCommand_Option_Version">
865+
<data name="DetailsCommand_Option_Version" xml:space="preserve">
866866
<value>Specifies a concrete version for displaying details. If not specified the last is taken.</value>
867867
</data>
868-
<data name="DetailsCommand_Property_Authors">
868+
<data name="DetailsCommand_Property_Authors" xml:space="preserve">
869869
<value>Authors</value>
870870
</data>
871-
<data name="DetailsCommand_Property_Description">
871+
<data name="DetailsCommand_Property_Description" xml:space="preserve">
872872
<value>Details</value>
873873
</data>
874-
<data name="DetailsCommand_Property_SourceFeed">
874+
<data name="DetailsCommand_Property_SourceFeed" xml:space="preserve">
875875
<value>Source Feed</value>
876876
</data>
877-
<data name="DetailsCommand_Property_Version">
877+
<data name="DetailsCommand_Property_Version" xml:space="preserve">
878878
<value>Package version</value>
879879
</data>
880-
<data name="DetailsCommand_Property_PrefixReserved">
880+
<data name="DetailsCommand_Property_PrefixReserved" xml:space="preserve">
881881
<value>Reserved</value>
882882
</data>
883-
<data name="DetailsCommand_Property_Languages">
883+
<data name="DetailsCommand_Property_Languages" xml:space="preserve">
884884
<value>Languages</value>
885-
<comment></comment>
886885
</data>
887-
<data name="DetailsCommand_Property_LicenseMetadata">
886+
<data name="DetailsCommand_Property_LicenseMetadata" xml:space="preserve">
888887
<value>License Metadata</value>
889888
</data>
890-
<data name="DetailsCommand_Property_LicenseExpression">
889+
<data name="DetailsCommand_Property_LicenseExpression" xml:space="preserve">
891890
<value>License Expression</value>
892891
</data>
893-
<data name="DetailsCommand_Property_License">
892+
<data name="DetailsCommand_Property_License" xml:space="preserve">
894893
<value>License</value>
895894
</data>
896-
<data name="DetailsCommand_Property_LicenseUrl">
895+
<data name="DetailsCommand_Property_LicenseUrl" xml:space="preserve">
897896
<value>License Url</value>
898897
</data>
899-
<data name="DetailsCommand_Property_Owners">
898+
<data name="DetailsCommand_Property_Owners" xml:space="preserve">
900899
<value>Owners</value>
901900
</data>
902-
<data name="DetailsCommand_Property_RepoUrl">
901+
<data name="DetailsCommand_Property_RepoUrl" xml:space="preserve">
903902
<value>Repository Url</value>
904903
</data>
905-
<data name="DetailsCommand_Property_ShortNames">
904+
<data name="DetailsCommand_Property_ShortNames" xml:space="preserve">
906905
<value>Short Names</value>
907-
<comment></comment>
908906
</data>
909-
<data name="DetailsCommand_Property_Tags">
907+
<data name="DetailsCommand_Property_Tags" xml:space="preserve">
910908
<value>Tags</value>
911-
<comment></comment>
912909
</data>
913-
<data name="DetailsCommand_Property_Templates">
910+
<data name="DetailsCommand_Property_Templates" xml:space="preserve">
914911
<value>Templates</value>
915912
</data>
916-
<data name="DetailsCommand_NoNuGetSources">
913+
<data name="DetailsCommand_NoNuGetSources" xml:space="preserve">
917914
<value>No NuGet sources are defined or enabled</value>
918915
</data>
919-
<data name="DetailsCommand_UnableToLoadResources">
916+
<data name="DetailsCommand_UnableToLoadResources" xml:space="preserve">
920917
<value>Failed to load NuGet sources configured for the folder {0}</value>
921918
</data>
922-
<data name="DetailsCommand_UnableToLoadResource">
919+
<data name="DetailsCommand_UnableToLoadResource" xml:space="preserve">
923920
<value>Could not parse NuGet source '{0}', so it was discarded</value>
924921
</data>
925922
<data name="OperationCancelled" xml:space="preserve">
@@ -947,4 +944,10 @@ The header is followed by the list of parameters and their errors (might be seve
947944
<value>Trusted</value>
948945
<comment>information about NuGet package origin; if a package has PrefixReserved indicator </comment>
949946
</data>
950-
</root>
947+
<data name="PostAction_ModifyJson_Error_ArgumentNotBoolean" xml:space="preserve">
948+
<value>Post action argument '{0}' is not a valid boolean value.</value>
949+
</data>
950+
<data name="PostAction_ModifyJson_Verbose_AttemptingToFindJsonFile" xml:space="preserve">
951+
<value>Attempting to find json file '{0}' in '{1}'</value>
952+
</data>
953+
</root>

src/Cli/Microsoft.TemplateEngine.Cli/PostActionProcessors/AddJsonPropertyPostActionProcessor.cs

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text.Encodings.Web;
55
using System.Text.Json;
66
using System.Text.Json.Nodes;
7+
78
using Microsoft.DotNet.Cli.Utils;
89
using Microsoft.TemplateEngine.Abstractions;
910
using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem;
@@ -12,6 +13,8 @@ namespace Microsoft.TemplateEngine.Cli.PostActionProcessors
1213
{
1314
internal class AddJsonPropertyPostActionProcessor : PostActionProcessorBase
1415
{
16+
private const string AllowFileCreationArgument = "allowFileCreation";
17+
private const string AllowPathCreationArgument = "allowPathCreation";
1518
private const string JsonFileNameArgument = "jsonFileName";
1619
private const string ParentPropertyPathArgument = "parentPropertyPath";
1720
private const string NewJsonPropertyNameArgument = "newJsonPropertyName";
@@ -46,12 +49,25 @@ protected override bool ProcessInternal(
4649
return false;
4750
}
4851

49-
IReadOnlyList<string> jsonFiles = FindFilesInCurrentProjectOrSolutionFolder(environment.Host.FileSystem, outputBasePath, matchPattern: jsonFileName, maxAllowedAboveDirectories: 1);
52+
IReadOnlyList<string> jsonFiles = FindFilesInCurrentFolderOrParentFolder(environment.Host.FileSystem, outputBasePath, jsonFileName);
5053

5154
if (jsonFiles.Count == 0)
5255
{
53-
Reporter.Error.WriteLine(LocalizableStrings.PostAction_ModifyJson_Error_NoJsonFile);
54-
return false;
56+
if (!bool.TryParse(action.Args.GetValueOrDefault(AllowFileCreationArgument, "false"), out bool createFile))
57+
{
58+
Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, AllowFileCreationArgument));
59+
return false;
60+
}
61+
62+
if (!createFile)
63+
{
64+
Reporter.Error.WriteLine(LocalizableStrings.PostAction_ModifyJson_Error_NoJsonFile);
65+
return false;
66+
}
67+
68+
string newJsonFilePath = Path.Combine(outputBasePath, jsonFileName);
69+
environment.Host.FileSystem.WriteAllText(newJsonFilePath, "{}");
70+
jsonFiles = new List<string> { newJsonFilePath };
5571
}
5672

5773
if (jsonFiles.Count > 1)
@@ -73,7 +89,8 @@ protected override bool ProcessInternal(
7389
newJsonElementProperties!.ParentProperty,
7490
":",
7591
newJsonElementProperties.NewJsonPropertyName,
76-
newJsonElementProperties.NewJsonPropertyValue);
92+
newJsonElementProperties.NewJsonPropertyValue,
93+
action);
7794

7895
if (newJsonContent == null)
7996
{
@@ -87,7 +104,7 @@ protected override bool ProcessInternal(
87104
return true;
88105
}
89106

90-
private static JsonNode? AddElementToJson(IPhysicalFileSystem fileSystem, string targetJsonFile, string? propertyPath, string propertyPathSeparator, string newJsonPropertyName, string newJsonPropertyValue)
107+
private static JsonNode? AddElementToJson(IPhysicalFileSystem fileSystem, string targetJsonFile, string? propertyPath, string propertyPathSeparator, string newJsonPropertyName, string newJsonPropertyValue, IPostAction action)
91108
{
92109
JsonNode? jsonContent = JsonNode.Parse(fileSystem.ReadAllText(targetJsonFile), nodeOptions: null, documentOptions: DeserializerOptions);
93110

@@ -96,7 +113,13 @@ protected override bool ProcessInternal(
96113
return null;
97114
}
98115

99-
JsonNode? parentProperty = FindJsonNode(jsonContent, propertyPath, propertyPathSeparator);
116+
if (!bool.TryParse(action.Args.GetValueOrDefault(AllowPathCreationArgument, "false"), out bool createPath))
117+
{
118+
Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, AllowPathCreationArgument));
119+
return false;
120+
}
121+
122+
JsonNode? parentProperty = FindJsonNode(jsonContent, propertyPath, propertyPathSeparator, createPath);
100123

101124
if (parentProperty == null)
102125
{
@@ -116,7 +139,7 @@ protected override bool ProcessInternal(
116139
return jsonContent;
117140
}
118141

119-
private static JsonNode? FindJsonNode(JsonNode content, string? nodePath, string pathSeparator)
142+
private static JsonNode? FindJsonNode(JsonNode content, string? nodePath, string pathSeparator, bool createPath)
120143
{
121144
if (nodePath == null)
122145
{
@@ -134,18 +157,22 @@ protected override bool ProcessInternal(
134157
return null;
135158
}
136159

137-
node = node[property];
160+
JsonNode? childNode = node[property];
161+
if (childNode is null && createPath)
162+
{
163+
node[property] = childNode = new JsonObject();
164+
}
165+
166+
node = childNode;
138167
}
139168

140169
return node;
141170
}
142171

143-
private static IReadOnlyList<string> FindFilesInCurrentProjectOrSolutionFolder(
172+
private static string[] FindFilesInCurrentFolderOrParentFolder(
144173
IPhysicalFileSystem fileSystem,
145174
string startPath,
146-
string matchPattern,
147-
Func<string, bool>? secondaryFilter = null,
148-
int maxAllowedAboveDirectories = 250)
175+
string matchPattern)
149176
{
150177
string? directory = fileSystem.DirectoryExists(startPath) ? startPath : Path.GetDirectoryName(startPath);
151178

@@ -158,22 +185,20 @@ private static IReadOnlyList<string> FindFilesInCurrentProjectOrSolutionFolder(
158185

159186
do
160187
{
161-
List<string> filesInDir = fileSystem.EnumerateFileSystemEntries(directory, matchPattern, SearchOption.AllDirectories).ToList();
162-
List<string> matches = new();
163-
164-
matches = secondaryFilter == null ? filesInDir : filesInDir.Where(x => secondaryFilter(x)).ToList();
188+
Reporter.Verbose.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Verbose_AttemptingToFindJsonFile, matchPattern, directory));
189+
string[] filesInDir = fileSystem.EnumerateFileSystemEntries(directory, matchPattern, SearchOption.AllDirectories).ToArray();
165190

166-
if (matches.Count > 0)
191+
if (filesInDir.Length > 0)
167192
{
168-
return matches;
193+
return filesInDir;
169194
}
170195

171196
directory = Path.GetPathRoot(directory) != directory ? Directory.GetParent(directory)?.FullName : null;
172197
numberOfUpLevels++;
173198
}
174-
while (directory != null && numberOfUpLevels <= maxAllowedAboveDirectories);
199+
while (directory != null && numberOfUpLevels <= 1);
175200

176-
return new List<string>();
201+
return Array.Empty<string>();
177202
}
178203

179204
private class JsonContentParameters

src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.cs.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.de.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.es.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/Microsoft.TemplateEngine.Cli/xlf/LocalizableStrings.fr.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)