@@ -119,7 +119,7 @@ public static void ValidateFileExists( ArgumentResult result )
119119 }
120120 }
121121
122- /// <summary>Extension method to add the <see cref="ValidateFolderExists(OptionResult)"/></summary>
122+ /// <summary>Extension method to add the <see cref="ValidateFolderExists(OptionResult)"/> validator </summary>
123123 /// <param name="self">Option to add the validator for</param>
124124 /// <returns><paramref name="self"/> for fluent use</returns>
125125 public static Option < DirectoryInfo > AcceptExistingFolderOnly ( this Option < DirectoryInfo > self )
@@ -149,5 +149,55 @@ public static void ValidateFolderExists( OptionResult result )
149149 }
150150 }
151151 }
152+
153+ /// <summary>Extension method to add the <see cref="EnsureFolderExists(OptionResult)"/> validator</summary>
154+ /// <param name="self">Option to add the validator for</param>
155+ /// <returns><paramref name="self"/> for fluent use</returns>
156+ public static Option < DirectoryInfo > EnsureFolder ( this Option < DirectoryInfo > self )
157+ {
158+ self . AddValidator ( EnsureFolderExists ) ;
159+ return self ;
160+ }
161+
162+ /// <summary>Option validator for an Option's tokens that ensures each Folder exists (creates it if not present)</summary>
163+ /// <param name="result">result to validate</param>
164+ /// <remarks>
165+ /// This is a parse validation that will create a directory that does not exist. It is explicitly NOT a security
166+ /// check/test!. Apps MUST NOT assume anything about the folder beyond the fact that it existed AT THE TIME this
167+ /// validation ran. It might not exist when needed, might have been replaced since, or may exist as or been
168+ /// replaced by a link to something else later or even deleted later. None of those scenarios is verified or
169+ /// prevented by this.
170+ /// </remarks>
171+ public static void EnsureFolderExists ( OptionResult result )
172+ {
173+ string value = result . Option . HelpName ?? result . Option . Name ;
174+ foreach ( Token token in result . Tokens )
175+ {
176+ if ( ! Directory . Exists ( token . Value ) )
177+ {
178+ try
179+ {
180+ Directory . CreateDirectory ( token . Value ) ;
181+ }
182+ catch ( Exception ex ) when ( IsDirectoryException ( ex ) )
183+ {
184+ result . AddError ( $ "Attempt to create directory '{ token . Value } ' resulted in { ex . Message } ") ;
185+ }
186+
187+ break ;
188+ }
189+ }
190+ }
191+
192+ // returns true if the exception is one of the documented types for Directory.CreateDirectory().
193+ private static bool IsDirectoryException ( Exception ex )
194+ {
195+ return ex is IOException or
196+ UnauthorizedAccessException or
197+ ArgumentException or
198+ PathTooLongException or
199+ DirectoryNotFoundException or
200+ NotSupportedException ;
201+ }
152202 }
153203}
0 commit comments