/*------------------------------------------------------------------------------ * Copyright © 2007 John Robbins -- All rights reserved. -----------------------------------------------------------------------------*/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.IO; using System.Diagnostics.CodeAnalysis; namespace Wintellect.Paraffin { internal class ParaffinArgParser : ArgParser { #region Required Creation Parameters /// /// The directory to process. /// public String StartDirectory { get; set; } /// /// The custom value to put on all components/files/dirs. /// public String CustomValue { get; set; } #endregion #region Optional Creation Parameters /// /// Override the DirectoryRef Id if you want the fragment files /// to go somewhere esle besides the INSTALLDIR. /// public String DirectoryRef { get; set; } /// /// The value to replace the starting directory in the File element /// src attribute. /// public String Alias { get; set; } /// /// If true, all the files in a directory will be included into a /// single component. /// public Boolean MultipleFilesPerComponent { get; set; } /// /// The list of extensions to skip. /// public Dictionary ExtensionList { get; set; } /// /// If true, GUIDs will be generated for all components. /// public Boolean GenerateGuids { get; set; } /// /// The amount to add to each component number to leave room for /// additional component files between directories. /// public Int32 IncrementValue { get; set; } /// /// If true, does not recurse the directories. /// public Boolean NoDirectoryRecursion { get; set; } /// /// The list of directories to exclude from the processing. /// public List DirectoryExcludeList { get; set; } /// /// If true, adds the Win64 attribute to components. /// public Boolean Win64 { get; set; } #endregion /// /// True if the user wants to update a previously created file. /// public Boolean Update { get; set; } /// /// The output filename. /// public String FileName { get; set; } // The private string to hold more detailed error information. private String errorMessage; // Indicates the error was found in OnDoneParse. private Boolean errorInOnDoneParse; // Indicates we've already seen the -inc switch. private Boolean seenIncrementSwitch; #region Command Line Option Constants private const string k_HELP_QUESTION = "?"; private const string k_HELP_SHORT = "h"; private const string k_HELP = "help"; private const string k_GUIDS = "guids"; private const string k_GUIDS_SHORT = "g"; private const string k_ALIAS = "alias"; private const string k_ALIAS_SHORT = "a"; private const string k_MULTIPLE = "multiple"; private const string k_MULTIPLE_SHORT = "m"; private const string k_NORECURSE = "norecurse"; private const string k_NORECURSE_SHORT = "nr"; private const string k_DIR = "dir"; private const string k_DIR_SHORT = "d"; private const string k_CUSTOM = "custom"; private const string k_CUSTOM_SHORT = "c"; private const string k_EXT = "ext"; private const string k_EXT_SHORT = "e"; private const string k_DIREXCLUDE = "direXclude"; private const string k_DIREXCLUDE_SHORT = "x"; private const string k_INC = "inc"; private const string k_INC_SHORT = "i"; private const string k_UPDATE = "update"; private const string k_UPDATE_SHORT = "u"; private const string k_WIN64 = "win64"; private const string k_DIRREF = "dirref"; private const string k_DIRREF_SHORT = "dr"; #endregion public ParaffinArgParser ( ) : base ( new String [] { k_HELP_QUESTION , k_HELP_SHORT , k_HELP , k_GUIDS_SHORT , k_GUIDS , k_MULTIPLE_SHORT , k_MULTIPLE , k_NORECURSE_SHORT , k_NORECURSE , k_UPDATE_SHORT , k_UPDATE , k_WIN64 } , new String [] { k_DIR_SHORT , k_DIR , k_CUSTOM_SHORT , k_CUSTOM , k_ALIAS_SHORT , k_ALIAS , k_EXT_SHORT , k_EXT , k_INC_SHORT , k_INC , k_DIREXCLUDE_SHORT , k_DIREXCLUDE , k_DIRREF , k_DIRREF_SHORT } , true ) { // Set all the appropriate defaults. FileName = String.Empty; StartDirectory = String.Empty; CustomValue = String.Empty; Alias = String.Empty; DirectoryRef = String.Empty; MultipleFilesPerComponent = false; ExtensionList = new Dictionary ( ); GenerateGuids = false; IncrementValue = 1; DirectoryExcludeList = new List ( ); errorMessage = String.Empty; } [SuppressMessage ( "Microsoft.Maintainability" , "CA1502:AvoidExcessiveComplexity" , Justification = "A switch statement using strings always generates complexity." )] protected override SwitchStatus OnSwitch ( string switchSymbol , string switchValue ) { SwitchStatus ss = SwitchStatus.NoError; switch ( switchSymbol ) { case k_HELP_QUESTION: case k_HELP_SHORT: case k_HELP: ss = SwitchStatus.ShowUsage; break; case k_GUIDS_SHORT: case k_GUIDS: GenerateGuids = true; break; case k_MULTIPLE_SHORT: case k_MULTIPLE: MultipleFilesPerComponent = true; break; case k_NORECURSE_SHORT: case k_NORECURSE: NoDirectoryRecursion = true; break; case k_UPDATE_SHORT: case k_UPDATE: Update = true; break; case k_WIN64: Win64 = true; break; case k_ALIAS_SHORT: case k_ALIAS: if ( false == String.IsNullOrEmpty ( Alias ) ) { errorMessage = Constants.AliasMultipleSwitches; ss = SwitchStatus.Error; } else { // If the alias does not end with a \, add one to help // the user out. if ( false == switchValue.EndsWith ( "\\" , StringComparison.OrdinalIgnoreCase ) ) { switchValue += "\\"; } Alias = switchValue; } break; case k_DIRREF_SHORT: case k_DIRREF: if ( false == String.IsNullOrEmpty ( DirectoryRef ) ) { errorMessage = Constants.DirectoryRefMultipleSwitches; ss = SwitchStatus.Error; } else { DirectoryRef = switchValue; } break; case k_DIR_SHORT: case k_DIR: if ( false == String.IsNullOrEmpty ( StartDirectory ) ) { errorMessage = Constants.DirectoryMultipleSwitches; ss = SwitchStatus.Error; } else if ( true == String.IsNullOrEmpty ( switchValue ) ) { errorMessage = Constants.DirectoryCannotBeEmpty; ss = SwitchStatus.Error; } else { // If the directory does not end with a \, add one. if ( false == switchValue.EndsWith ( "\\" , StringComparison.OrdinalIgnoreCase ) ) { switchValue += "\\"; } StartDirectory = switchValue; } break; case k_CUSTOM_SHORT: case k_CUSTOM: if ( false == String.IsNullOrEmpty ( CustomValue ) ) { errorMessage = Constants.UniqueMultipleSwitches; ss = SwitchStatus.Error; } else if ( true == String.IsNullOrEmpty ( switchValue ) ) { errorMessage = Constants.UniqueCannotBeEmpty; ss = SwitchStatus.Error; } else if ( switchValue.Length >= 65 ) { errorMessage = Constants.UniqueTooLong; ss = SwitchStatus.Error; } else { CustomValue = switchValue; } break; case k_EXT_SHORT: case k_EXT: if ( true == String.IsNullOrEmpty ( switchValue ) ) { errorMessage = Constants.ExtensionCannotBeEmpty; ss = SwitchStatus.Error; } else { // Does it start with a period? If not, add one to help // the user out. if ( '.' != switchValue [ 0 ] ) { switchValue = "." + switchValue; } // You can have as many -ext switches as you want. ExtensionList.Add ( switchValue.ToUpperInvariant ( ) , true ); } break; case k_INC_SHORT: case k_INC: if ( true == seenIncrementSwitch ) { errorMessage = Constants.IncrementMultipleSwitches; ss = SwitchStatus.Error; } else { Int32 level = 0; if ( false == Int32.TryParse ( switchValue , out level ) ) { errorMessage = Constants.IncrementNoParse; ss = SwitchStatus.Error; } else if ( level <= 0 ) { errorMessage = Constants.IncrementNotZero; ss = SwitchStatus.Error; } else { IncrementValue = level; seenIncrementSwitch = true; } } break; case k_DIREXCLUDE_SHORT: case k_DIREXCLUDE: DirectoryExcludeList.Add ( switchValue ); break; default: { errorMessage = Constants.UnknownCommandLineOption; ss = SwitchStatus.Error; } break; } return ( ss ); } protected override SwitchStatus OnNonSwitch ( string value ) { SwitchStatus ss = SwitchStatus.NoError; if ( false == String.IsNullOrEmpty ( FileName ) ) { errorMessage = Constants.OutputAlreadySpecified; ss = SwitchStatus.Error; } else if ( true == String.IsNullOrEmpty ( value ) ) { errorMessage = Constants.OutputCannotBeEmpty; ss = SwitchStatus.Error; } else { FileName = value; } // There are no non switches allowed. errorMessage = Constants.UnknownCommandLineOption; return ( ss ); } protected override SwitchStatus OnDoneParse ( ) { SwitchStatus ss = SwitchStatus.NoError; // The output file can never be null. if ( true == string.IsNullOrEmpty ( FileName ) ) { errorMessage = Constants.OutputCannotBeEmpty; ss = SwitchStatus.Error; errorInOnDoneParse = true; } else if ( false == Update ) { // Check that I at least have a directory and prefix. Everything // else is optional when updating files. if ( true == String.IsNullOrEmpty ( StartDirectory ) ) { errorMessage = Constants.DirectoryCannotBeEmpty; ss = SwitchStatus.Error; errorInOnDoneParse = true; } else if ( false == Directory.Exists ( StartDirectory ) ) { errorMessage = Constants.DirectoryDoesNotExist; ss = SwitchStatus.Error; errorInOnDoneParse = true; } else if ( true == String.IsNullOrEmpty ( CustomValue ) ) { errorMessage = Constants.UniqueCannotBeEmpty; ss = SwitchStatus.Error; errorInOnDoneParse = true; } } else { // The user is asking to update. // Check that they didn't also specify creation options. if ( ( false == String.IsNullOrEmpty ( StartDirectory ) || ( false == String.IsNullOrEmpty ( CustomValue ) ) ) ) { errorMessage = Constants.MutuallyExclusiveOptions; ss = SwitchStatus.Error; errorInOnDoneParse = true; } // Check to at least see if the file exists. if ( false == File.Exists ( FileName ) ) { errorMessage = Constants.UpdateFileMustExist; ss = SwitchStatus.Error; errorInOnDoneParse = true; } } return ( ss ); } public override void OnUsage ( string errorInfo ) { ProcessModule exe = Process.GetCurrentProcess ( ).Modules [ 0 ]; Console.WriteLine ( Constants.UsageString , exe.FileVersionInfo.FileVersion ); if ( ( false == errorInOnDoneParse ) && ( false == String.IsNullOrEmpty ( errorInfo ) ) ) { Console.WriteLine ( ); Console.WriteLine ( Constants.ErrorSwitch , errorInfo ); } if ( false == String.IsNullOrEmpty ( errorMessage ) ) { Console.WriteLine ( ); Console.WriteLine ( errorMessage ); } } } }