/*------------------------------------------------------------------------------
* 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 );
}
}
}
}