-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JsonPropertyPostAction: allow to create file and path #41959
Changes from all commits
ad027ef
e7aa57d
cf1cc5e
3b4ce6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
using System.Text.Encodings.Web; | ||
using System.Text.Json; | ||
using System.Text.Json.Nodes; | ||
|
||
using Microsoft.DotNet.Cli.Utils; | ||
using Microsoft.TemplateEngine.Abstractions; | ||
using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem; | ||
|
@@ -12,6 +13,8 @@ namespace Microsoft.TemplateEngine.Cli.PostActionProcessors | |
{ | ||
internal class AddJsonPropertyPostActionProcessor : PostActionProcessorBase | ||
{ | ||
private const string AllowFileCreationArgument = "allowFileCreation"; | ||
private const string AllowPathCreationArgument = "allowPathCreation"; | ||
private const string JsonFileNameArgument = "jsonFileName"; | ||
private const string ParentPropertyPathArgument = "parentPropertyPath"; | ||
private const string NewJsonPropertyNameArgument = "newJsonPropertyName"; | ||
|
@@ -46,12 +49,25 @@ protected override bool ProcessInternal( | |
return false; | ||
} | ||
|
||
IReadOnlyList<string> jsonFiles = FindFilesInCurrentProjectOrSolutionFolder(environment.Host.FileSystem, outputBasePath, matchPattern: jsonFileName, maxAllowedAboveDirectories: 1); | ||
IReadOnlyList<string> jsonFiles = FindFilesInCurrentFolderOrParentFolder(environment.Host.FileSystem, outputBasePath, jsonFileName); | ||
|
||
if (jsonFiles.Count == 0) | ||
{ | ||
Reporter.Error.WriteLine(LocalizableStrings.PostAction_ModifyJson_Error_NoJsonFile); | ||
return false; | ||
if (!bool.TryParse(action.Args.GetValueOrDefault(AllowFileCreationArgument, "false"), out bool createFile)) | ||
{ | ||
Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, AllowFileCreationArgument)); | ||
return false; | ||
} | ||
|
||
if (!createFile) | ||
{ | ||
Reporter.Error.WriteLine(LocalizableStrings.PostAction_ModifyJson_Error_NoJsonFile); | ||
return false; | ||
} | ||
|
||
string newJsonFilePath = Path.Combine(outputBasePath, jsonFileName); | ||
environment.Host.FileSystem.WriteAllText(newJsonFilePath, "{}"); | ||
jsonFiles = new List<string> { newJsonFilePath }; | ||
} | ||
|
||
if (jsonFiles.Count > 1) | ||
|
@@ -73,7 +89,8 @@ protected override bool ProcessInternal( | |
newJsonElementProperties!.ParentProperty, | ||
":", | ||
newJsonElementProperties.NewJsonPropertyName, | ||
newJsonElementProperties.NewJsonPropertyValue); | ||
newJsonElementProperties.NewJsonPropertyValue, | ||
action); | ||
|
||
if (newJsonContent == null) | ||
{ | ||
|
@@ -87,7 +104,7 @@ protected override bool ProcessInternal( | |
return true; | ||
} | ||
|
||
private static JsonNode? AddElementToJson(IPhysicalFileSystem fileSystem, string targetJsonFile, string? propertyPath, string propertyPathSeparator, string newJsonPropertyName, string newJsonPropertyValue) | ||
private static JsonNode? AddElementToJson(IPhysicalFileSystem fileSystem, string targetJsonFile, string? propertyPath, string propertyPathSeparator, string newJsonPropertyName, string newJsonPropertyValue, IPostAction action) | ||
{ | ||
JsonNode? jsonContent = JsonNode.Parse(fileSystem.ReadAllText(targetJsonFile), nodeOptions: null, documentOptions: DeserializerOptions); | ||
|
||
|
@@ -96,7 +113,13 @@ protected override bool ProcessInternal( | |
return null; | ||
} | ||
|
||
JsonNode? parentProperty = FindJsonNode(jsonContent, propertyPath, propertyPathSeparator); | ||
if (!bool.TryParse(action.Args.GetValueOrDefault(AllowPathCreationArgument, "false"), out bool createPath)) | ||
{ | ||
Reporter.Error.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Error_ArgumentNotBoolean, AllowPathCreationArgument)); | ||
return false; | ||
} | ||
|
||
JsonNode? parentProperty = FindJsonNode(jsonContent, propertyPath, propertyPathSeparator, createPath); | ||
|
||
if (parentProperty == null) | ||
{ | ||
|
@@ -116,7 +139,7 @@ protected override bool ProcessInternal( | |
return jsonContent; | ||
} | ||
|
||
private static JsonNode? FindJsonNode(JsonNode content, string? nodePath, string pathSeparator) | ||
private static JsonNode? FindJsonNode(JsonNode content, string? nodePath, string pathSeparator, bool createPath) | ||
{ | ||
if (nodePath == null) | ||
{ | ||
|
@@ -134,18 +157,22 @@ protected override bool ProcessInternal( | |
return null; | ||
} | ||
|
||
node = node[property]; | ||
JsonNode? childNode = node[property]; | ||
if (childNode is null && createPath) | ||
{ | ||
node[property] = childNode = new JsonObject(); | ||
} | ||
|
||
node = childNode; | ||
} | ||
|
||
return node; | ||
} | ||
|
||
private static IReadOnlyList<string> FindFilesInCurrentProjectOrSolutionFolder( | ||
private static string[] FindFilesInCurrentFolderOrParentFolder( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed to better match actual logic in place. |
||
IPhysicalFileSystem fileSystem, | ||
string startPath, | ||
string matchPattern, | ||
Func<string, bool>? secondaryFilter = null, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused. |
||
int maxAllowedAboveDirectories = 250) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was forced to 1 on the only calling place. |
||
string matchPattern) | ||
{ | ||
string? directory = fileSystem.DirectoryExists(startPath) ? startPath : Path.GetDirectoryName(startPath); | ||
|
||
|
@@ -158,22 +185,20 @@ private static IReadOnlyList<string> FindFilesInCurrentProjectOrSolutionFolder( | |
|
||
do | ||
{ | ||
List<string> filesInDir = fileSystem.EnumerateFileSystemEntries(directory, matchPattern, SearchOption.AllDirectories).ToList(); | ||
List<string> matches = new(); | ||
|
||
matches = secondaryFilter == null ? filesInDir : filesInDir.Where(x => secondaryFilter(x)).ToList(); | ||
Reporter.Verbose.WriteLine(string.Format(LocalizableStrings.PostAction_ModifyJson_Verbose_AttemptingToFindJsonFile, matchPattern, directory)); | ||
string[] filesInDir = fileSystem.EnumerateFileSystemEntries(directory, matchPattern, SearchOption.AllDirectories).ToArray(); | ||
|
||
if (matches.Count > 0) | ||
if (filesInDir.Length > 0) | ||
{ | ||
return matches; | ||
return filesInDir; | ||
} | ||
|
||
directory = Path.GetPathRoot(directory) != directory ? Directory.GetParent(directory)?.FullName : null; | ||
numberOfUpLevels++; | ||
} | ||
while (directory != null && numberOfUpLevels <= maxAllowedAboveDirectories); | ||
while (directory != null && numberOfUpLevels <= 1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It'd be good to have a better walk-up logic but I couldn't think of anything that would work for all/most cases.
|
||
|
||
return new List<string>(); | ||
return Array.Empty<string>(); | ||
} | ||
|
||
private class JsonContentParameters | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Split into 2 properties to allow users to be able to add the missing property path without forcing requirement to allow file creation.
There is some potential discussion here because it's not really making sense to allow file creation and not allow path creation so we could maybe have some kind of enum instead (e.g.
CreationMode
withNone
being the default,Path
andFile
orFileAndPath
). We could also keep the boolean and say theallowPathCreation
is assumed to betrue
whenallowFileCreation
is set totrue
.