/*
* Filename: CommandLineArgs.cs
* Product: Versioning Controlled Build
* Solution: BuildAutoIncrement
* Project: CommandLine
* Description: Class that parses command-line arguments.
* Copyright: Julijan �ribar, 2004-2013
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the author(s) be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Resources;
using System.Text;
namespace BuildAutoIncrement {
/// <summary>
/// Class representing arguments passed to command line tool.
/// </summary>
public sealed class CommandLineArgs {
private class DuplicateArgumentException : ArgumentException {
public DuplicateArgumentException(string message) : base(message) {
}
}
/// <summary>
/// Enumeration for project synchronization.
/// </summary>
public enum ProjectsSynchronization {
NotDefined,
Synchronize,
IncrementAndSynchronize,
None
}
#region ProjectsNameList
/// <summary>
/// A list of strings used for case insensitive project names
/// comparison.
/// </summary>
private class ProjectsNameList : ArrayList {
/// <summary>
/// Overrides <c>Contains</c> method to do case insensitive check.
/// </summary>
/// <param name="name">
/// String to check.
/// </param>
/// <returns>
/// <c>true</c> if string is found in the list, otherwise <c>false</c>.
/// </returns>
public override bool Contains(object name) {
Debug.Assert(name is string);
foreach (string item in this) {
if (string.Compare((string)name, item, true) == 0)
return true;
}
return false;
}
}
#endregion // ProjectsNameList
#region CommandLineSwitchesTable
/// <summary>
/// Enumeration representing command-line switches.
/// </summary>
enum CommandLineSwitch {
Empty,
Gui,
Apply,
Projects,
Synchronize,
VersionTypes,
DisplaySummary,
SourceSafeUser,
CheckProjectsExistance
}
/// <summary>
/// Table with all possible command-line switches.
/// </summary>
private class CommandLineSwitchesTable : Hashtable {
/// <summary>
/// Initializes <c>CommandLineSwitchesTable</c> object.
/// </summary>
// NOTE: all switches must be in lower case!
public CommandLineSwitchesTable() {
this[CommandLineSwitch.Gui] = "/g"; // Start GUI
this[CommandLineSwitch.Projects] = "/p"; // Projects for which versions may be modified:
// projects comma separated list of projects to which
// modifications are restricted
this[CommandLineSwitch.Apply] = "/a"; // Apply versions to:
// A all projects
// M modified projects only (default)
this[CommandLineSwitch.VersionTypes] = "/v"; // Version types to modify:
// * all version types (see below)
// A Assembly version
// P Product (Informational) version
// F File version
this[CommandLineSwitch.Synchronize] = "/s"; // Synchronize versions:
// S Synchronize
// I Increment and then synchronize
// N No synchronization
this[CommandLineSwitch.DisplaySummary] = "/m"; // Display summary:
// C console (default)
// F file (with optional filename may be provided)
// N none
this[CommandLineSwitch.SourceSafeUser] = "/u"; // Provide username and/or password. If nothing provided, this
// causes username/password prompt
this[CommandLineSwitch.CheckProjectsExistance] = "/c"; // Check if projects provided by some switches exist:
// E check files (default). In case of error, command is
// not executed
// W do not check; only warning is issued.
}
/// <summary>
/// Outputs brief description of command-line utility to console.
/// </summary>
/// <param name="executableName">
/// Utility executable name.
/// </param>
public static void OutputDescription(string executableName) {
Console.WriteLine(string.Format("{0} /G [solution]", executableName));
Console.WriteLine(string.Format("{0} [solution [version]] [/P:projects] [/C:(E|W)] [/A:(A|M)]", executableName));
Console.WriteLine(" [/V:(*|[A][F][P|I])] [/S:(S|I|N)] [/M:([C][F[\"filename\"]]|N)]");
Console.WriteLine(" [/U[:(username[,password])]]");
Console.WriteLine();
Console.WriteLine(" solution Solution file (.SLN or .DSW) for which versions should be updated.");
Console.WriteLine(" /G Starts GUI form with a list of all projects.");
Console.WriteLine(" version Version pattern to be applied, e.g. \"1.2.*.+2\".");
Console.WriteLine(" /P Specification for individual projects.");
Console.WriteLine(" projects List of comma separated project names prefixed by:");
Console.WriteLine(" + (optional) include into the list of projects for which");
Console.WriteLine(" version may be modified;");
Console.WriteLine(" - include into the list of projects for which version must");
Console.WriteLine(" not be modified;");
Console.WriteLine(" ! include into the list of projects for which version is");
Console.WriteLine(" allways modified.");
Console.WriteLine(" /C Checks if project names provided with /P switch exist in solution.");
Console.WriteLine(" Any invalid name causes:");
Console.WriteLine(" E Error - command is not executed (default);");
Console.WriteLine(" W Warning - command is executed ignoring invalid entries.");
Console.WriteLine(" /A Applies version to:");
Console.WriteLine(" A All projects;");
Console.WriteLine(" M Modified projects only (default).");
Console.WriteLine(" /V Version types to modify:");
Console.WriteLine(" A Assembly version;");
Console.WriteLine(" P or I Product (Informational) version;");
Console.WriteLine(" F File version;");
Console.WriteLine(" * All version types.");
Console.WriteLine(" /S Synchronization of versions for projects:");
Console.WriteLine(" S Synchronize (to the highest version);");
Console.WriteLine(" I Increment and then synchronize;");
Console.WriteLine(" N Increment versions independently.");
Console.WriteLine(" /M Version update summary:");
Console.WriteLine(" C Output to console (default);");
Console.WriteLine(" F Write to a file (with optional filename);");
Console.WriteLine(" N Suppress the summary.");
Console.WriteLine(" /U SourceSafe username and password.");
Console.WriteLine();
}
/// <summary>
/// Hides base class <c>ContainsValue</c> method to ensure type
/// safety.
/// </summary>
/// <param name="value">
/// Value to check.
/// </param>
/// <returns>
/// <c>true</c> if value exists, otherwise <c>false</c>.
/// </returns>
private new bool ContainsValue(object value) {
Debug.Assert(value is string);
return ContainsValue((string)value);
}
/// <summary>
/// Checks if a switch exists in the table. Comparison is case
/// insensitive.
/// </summary>
/// <param name="value">
/// Value to check.
/// </param>
/// <returns>
/// <c>true</c> if value exists, otherwise <c>false</c>.
/// </returns>
public bool ContainsValue(string value) {
return base.ContainsValue(value.ToLower());
}
/// <summary>
/// Hides base class <c>ContainsKey</c> method to ensure type
/// safety.
/// </summary>
/// <param name="key">
/// Key to check.
/// </param>
/// <returns>
/// <c>true</c> if key exists, otherwise <c>false</c>.
/// </returns>
private new bool ContainsKey(object key) {
Debug.Assert(key is CommandLineSwitch);
return ContainsKey((CommandLineSwitch)key);
}
/// <summary>
/// Checks if a key exists in the table.
/// </summary>
/// <param name="key">
/// Key to check.
/// </param>
/// <returns>
/// <c>true</c> if key exists, otherwise <c>false</c>.
/// </returns>
public bool ContainsKey(CommandLineSwitch key) {
return base.ContainsKey(key);
}
/// <summary>
/// Overides base class indexer to assure type-safe access.
/// </summary>
private new object this[object key] {
get {
Debug.Assert(key is CommandLineSwitch);
return this[(CommandLineSwitch)key];
}
set {
Debug.Assert(key is CommandLineSwitch);
Debug.Assert(value is string);
this[(CommandLineSwitch)key] = (string)value;
}
}
/// <summary>
/// Type-safe indexer to access value by key.
/// </summary>
public string this[CommandLineSwitch key] {
get {
return (string)base[key];
}
set {
base[key] = value;
}
}
/// <summary>
/// Gets a key for a string provided.
/// </summary>
/// <param name="switchString">
/// Switch string for which <c>CommandLineSwitch</c> is requested.
/// Search is case insesitive.
/// </param>
/// <returns>
/// <c>CommandLineSwitch</c> that corresponds to switch string
/// provided or <c>CommandLineSwitch.Empty</c> if switch is not
/// found.
/// </returns>
public CommandLineSwitch GetKey(string switchString) {
string sw = switchString.ToLower();
Debug.Assert(ContainsValue(switchString));
IDictionaryEnumerator en = base.GetEnumerator();
while (en.MoveNext()) {
Debug.Assert(en.Value is string);
Debug.Assert(en.Key is CommandLineSwitch);
if ((string)en.Value == sw)
return (CommandLineSwitch)en.Key;
}
Debug.Assert(false, string.Format("Unknown command-line switch {0}", switchString));
return CommandLineSwitch.Empty;
}
}
#endregion // CommandLineSwitchesTable
#region Constructors
/// <summary>
/// Initializes <c>CommandLineArgs</c> object.
/// </summary>
private CommandLineArgs() {
CommandLineSwitches = new CommandLineSwitchesTable();
m_solutionFilename = string.Empty;
m_newVersion = string.Empty;
m_applyToTypes = AssemblyVersionType.None;
m_projectsAllowedForVersionModification = new ProjectsNameList();
m_projectsToExclude = new ProjectsNameList();
m_projectsToForce = new ProjectsNameList();
m_displaySummary = new DisplaySummaryOptions();
m_sourceSafeUserOptions = new SourceSafeUserOptions();
m_checkProjectsExistance = true;
m_projectsSynchronization = ProjectsSynchronization.NotDefined;
}
public CommandLineArgs(string[] args) : this() {
ParseArguments(args);
}
#endregion // Constructors
#region Public properties
/// <summary>
/// Gets solution filename if provided by command-line arguments
/// or an empty string.
/// </summary>
public string SolutionFilename {
get {
return m_solutionFilename;
}
}
/// <summary>
/// Gets new version if provided by command-line arguments or an
/// empty string.
/// </summary>
public string NewVersion {
get {
return m_newVersion;
}
}
/// <summary>
/// Returns <c>true</c> if start GUI switch is set.
/// </summary>
public bool StartGui {
get {
return m_startGui;
}
}
/// <summary>
/// Returns <c>true</c> if versioning should be applied to all
/// projects or <c>false</c> if versioning should be applied to
/// modified projects only.
/// </summary>
public bool ApplyToAllProjects {
get {
return m_applyToAllProjects;
}
}
/// <summary>
/// Returns combination of <c>AssemblyVersionType</c> flags defining
/// on which version types (AssemblyInfo, AssemblyFile or/and
/// AssemblyInformational) should version be applied.
/// </summary>
public AssemblyVersionType ApplyToTypes {
get {
return m_applyToTypes;
}
}
/// <summary>
/// Gets <c>ProjectsSynchronization</c> enumeration that determines
/// how projects are synchronized.
/// </summary>
public ProjectsSynchronization SynchronizeProjects {
get {
return m_projectsSynchronization;
}
}
/// <summary>
/// Gets an array of project names allowed for versioning.
/// </summary>
public string[] ProjectsAllowedForVersionModification {
get {
return (string[])m_projectsAllowedForVersionModification.ToArray(typeof(string));
}
}
/// <summary>
/// Gets an array of project names not allowed for versioning.
/// </summary>
public string[] ProjectsToExclude {
get {
return (string[])m_projectsToExclude.ToArray(typeof(string));
}
}
/// <summary>
/// Gets an array of project names that must be versioned.
/// </summary>
public string[] ProjectsToForce {
get {
return (string[])m_projectsToForce.ToArray(typeof(string));
}
}
/// <summary>
/// Gets <c>DisplaySummaryOptions</c> object that determines how
/// version update summary is displayed.
/// </summary>
public DisplaySummaryOptions DisplaySummaryOptions {
get {
return m_displaySummary;
}
}
/// <summary>
/// Gets <c>SourceSafeUserOptions</c> with SourceSafe username and
/// password.
/// </summary>
public SourceSafeUserOptions SourceSafeUserOptions {
get {
return m_sourceSafeUserOptions;
}
}
/// <summary>
/// Returns <c>true</c> if existance of individual projects provided
/// in project list must be checked, otherwise <c>false</c>.
/// </summary>
public bool CheckProjectsExistance {
get {
return m_checkProjectsExistance;
}
}
#endregion Public properties
#region Private methods
/// <summary>
/// parses arfuments provided to commad line.
/// </summary>
/// <param name="args">
/// An array of strings.
/// </param>
private void ParseArguments(string[] args) {
Debug.Assert(args != null);
ArrayList switches = new ArrayList();
foreach (string arg in args) {
if (arg.StartsWith("/")) {
string sw = arg.Substring(0, 2);
if (!CommandLineSwitches.ContainsValue(sw))
throw new InvalidCommandLineArgumentException(string.Format(UnknownSwitch, arg));
CommandLineSwitch cls = CommandLineSwitches.GetKey(sw);
if (switches.IndexOf(cls) != -1)
throw new InvalidCommandLineArgumentException(string.Format(DuplicateSwitch, sw));
switches.Add(cls);
ProcessCommandLineSwitch(arg);
}
else {
ProcessNonSwitchArgument(arg);
}
}
}
/// <summary>
/// Parses command-line arguments that do not start with '/'
/// character, i.e. solution name and version string.
/// </summary>
/// <param name="arg">
/// All arguments passed to command line.
/// </param>
private void ProcessNonSwitchArgument(string arg) {
// first non-switch argument should be the solution filename,
// followed by optional version string
if (m_solutionFilename.Length == 0) {
if (Path.IsPathRooted(arg))
m_solutionFilename = arg;
else
m_solutionFilename = Path.Combine(Environment.CurrentDirectory, arg);
if (!File.Exists(m_solutionFilename))
throw new FileNotFoundException(string.Format(FileNotFound, m_solutionFilename), m_solutionFilename);
}
else if (m_newVersion.Length == 0) {
m_newVersion = arg.Trim(new char[] { '\"', '\'' });
}
else {
throw new InvalidCommandLineArgumentException(string.Format(TooManyArguments, arg));
}
}
/// <summary>
/// Parses command-line switches, i.e. arguments that start with '/'
/// character.
/// </summary>
/// <param name="commandLineArg">
/// All arguments passed to command line.
/// </param>
private void ProcessCommandLineSwitch(string commandLineArg) {
string[] splitSwitch = commandLineArg.Split(':');
if (splitSwitch.Length > 2) {
int n = commandLineArg.IndexOf(':') + 1;
throw new InvalidCommandLineArgumentException(string.Format(InvalidSwitchFormat, splitSwitch[0], commandLineArg.Substring(n)));
}
try {
switch (CommandLineSwitches.GetKey(splitSwitch[0])) {
case CommandLineSwitch.Gui:
if (splitSwitch.Length > 1) {
int n = commandLineArg.IndexOf(':') + 1;
throw new InvalidCommandLineArgumentException(string.Format(InvalidSwitchFormat, splitSwitch[0], commandLineArg.Substring(n)));
}
m_startGui = true;
return;
case CommandLineSwitch.Apply:
if (splitSwitch.Length == 1 || splitSwitch[1].Length == 0)
throw new ArgumentNullException();
ParseApplySwitch(splitSwitch[1]);
return;
case CommandLineSwitch.Synchronize:
if (splitSwitch.Length == 1 || splitSwitch[1].Length == 0)
throw new ArgumentNullException();
ParseSynchronizationSwitch(splitSwitch[1]);
return;
case CommandLineSwitch.Projects:
if (splitSwitch.Length == 1 || splitSwitch[1].Length == 0)
throw new ArgumentNullException();
ParseProjectsList(splitSwitch[1]);
return;
case CommandLineSwitch.VersionTypes:
if (splitSwitch.Length == 1 || splitSwitch[1].Length == 0)
throw new ArgumentNullException();
ParseVersionSwitch(splitSwitch[1]);
return;
case CommandLineSwitch.DisplaySummary:
if (splitSwitch.Length == 1 || splitSwitch[1].Length == 0)
throw new ArgumentNullException();
m_displaySummary = ParseDisplaySummaryOptions(splitSwitch[1]);
return;
case CommandLineSwitch.SourceSafeUser:
if (splitSwitch.Length > 1 && splitSwitch[1].Length == 0)
throw new ArgumentNullException();;
// if only '/u' provided
if (splitSwitch.Length == 1 || splitSwitch[1].Length == 0)
m_sourceSafeUserOptions = new SourceSafeUserOptions(true);
else
m_sourceSafeUserOptions = ParseSourceSafeOptions(splitSwitch[1]);
return;
case CommandLineSwitch.CheckProjectsExistance:
if (splitSwitch.Length == 1 || splitSwitch[1].Length == 0)
throw new ArgumentNullException();
m_checkProjectsExistance = ParseCheckProjectsExistance(splitSwitch[1]);
return;
default:
throw new InvalidCommandLineArgumentException(string.Format(UnknownSwitch, splitSwitch[0]));
}
}
catch (FormatException exception) {
throw new InvalidCommandLineArgumentException(string.Format(InvalidSwitchFormat, splitSwitch[0], exception.Message));
}
catch (DuplicateArgumentException exception) {
throw new InvalidCommandLineArgumentException(string.Format(ErrorInSwitch, splitSwitch[0], exception.Message));
}
catch (ArgumentNullException) {
throw new InvalidCommandLineArgumentException(string.Format(SwitchHasNoValue, splitSwitch[0]));
}
catch (ArgumentException exception) {
throw new InvalidCommandLineArgumentException(string.Format(InvalidSwitchValue, splitSwitch[0], exception.Message));
}
}
/// <summary>
/// Parses switch that defines to which projects version should be
/// applied.
/// </summary>
/// <param name="switchValue">
/// Value provided with the switch.
/// </param>
private void ParseApplySwitch(string switchValue) {
Debug.Assert(switchValue != null && switchValue.Length > 0);
switch (switchValue) {
case "a":
case "A":
m_applyToAllProjects = true;
break;
case "m":
case "M":
break;
default:
throw new ArgumentException(switchValue);
}
}
/// <summary>
/// Parses switch that defines to which version types versioning
/// should be applied.
/// </summary>
/// <param name="switchValue">
/// Switch value to be parsed.
/// </param>
private void ParseVersionSwitch(string switchValue) {
Debug.Assert(switchValue != null && switchValue.Length > 0);
if (switchValue == "*") {
m_applyToTypes = AssemblyVersionType.All;
return;
}
for (int i = 0; i < switchValue.Length; i++) {
char ch = switchValue[i];
switch (ch) {
case 'a':
case 'A':
SetVersionToApplyTo(AssemblyVersionType.AssemblyVersion);
break;
case 'p':
case 'P':
case 'i':
case 'I':
SetVersionToApplyTo(AssemblyVersionType.AssemblyInformationalVersion);
break;
case 'f':
case 'F':
SetVersionToApplyTo(AssemblyVersionType.AssemblyFileVersion);
break;
case '*':
throw new FormatException(AsteriskValueMustbeAlone);
default:
throw new ArgumentException(string.Format(InvalidSwitchValue, ch));
}
}
}
/// <summary>
/// Parses list provided with projects list.
/// </summary>
/// <param name="switchValue">
/// Value to parse
/// </param>
private void ParseProjectsList(string switchValue) {
Debug.Assert(switchValue != null && switchValue.Length > 0);
foreach (string s in switchValue.Split(',')) {
string projectName = null;
switch (s[0]) {
case '-':
projectName = ExtractProjectName(s.Substring(1));
CheckProjectNameAlreadyExists(projectName);
m_projectsToExclude.Add(projectName);
break;
case '!':
projectName = ExtractProjectName(s.Substring(1));
CheckProjectNameAlreadyExists(projectName);
m_projectsToForce.Add(projectName);
break;
case '+':
projectName = ExtractProjectName(s.Substring(1));
CheckProjectNameAlreadyExists(projectName);
m_projectsAllowedForVersionModification.Add(projectName);
break;
default:
projectName = ExtractProjectName(s);
CheckProjectNameAlreadyExists(projectName);
m_projectsAllowedForVersionModification.Add(projectName);
break;
}
}
}
/// <summary>
/// Extracts project name, trimming optional quotes. In case of
/// invalid format, <c>FormatException</c> is thrown.
/// </summary>
/// <param name="toExtract">
/// String to trim.
/// </param>
/// <returns>
/// Project name.
/// </returns>
private string ExtractProjectName(string toExtract) {
if (toExtract.StartsWith("\"") != toExtract.EndsWith("\""))
throw new FormatException(string.Format(NotEnclosedByQuotes, toExtract.Trim('\"')));
return toExtract.Trim('\"');
}
/// <summary>
/// Checks if project name provided already exists in one of internal
/// lists. If exists, <c>ArgumentException</c> is thrown.
/// </summary>
/// <param name="name">
/// Name to check.
/// </param>
private void CheckProjectNameAlreadyExists(string name) {
if (m_projectsAllowedForVersionModification.Contains(name) || m_projectsToExclude.Contains(name) || m_projectsToForce.Contains(name)) {
throw new DuplicateArgumentException(string.Format(ProjectNameAlreadySpecified, name));
}
}
/// <summary>
/// Sets version type flags to apply.
/// </summary>
/// <param name="assemblyVersionType">
/// <c>AssemblyVersionType</c> to apply.
/// </param>
private void SetVersionToApplyTo(AssemblyVersionType assemblyVersionType) {
if ((m_applyToTypes & assemblyVersionType) == assemblyVersionType)
throw new FormatException(string.Format(VersionFlagAlreadySet, assemblyVersionType.ToString()));
m_applyToTypes |= assemblyVersionType;
}
/// <summary>
/// Parses Synchronization switch. Allowed forms (all preceeded by '/s:'):
/// S synchronize
/// I increment and then synchronize
/// N increment indepentantly
/// </summary>
/// <param name="switchValue">
/// </param>
private void ParseSynchronizationSwitch(string switchValue) {
Debug.Assert(switchValue != null && switchValue.Length > 0);
switch (switchValue) {
case "i":
case "I":
m_projectsSynchronization = ProjectsSynchronization.IncrementAndSynchronize;
return;
case "s":
case "S":
m_projectsSynchronization = ProjectsSynchronization.Synchronize;
return;
case "n":
case "N":
m_projectsSynchronization = ProjectsSynchronization.None;
return;
default:
throw new ArgumentException(switchValue);
}
}
/// <summary>
/// Parses summary display options. Allowed forms (all preceeded by '/m':'):
/// C - only to console (default)
/// F["filename"] - to file, with optional filename
/// CF["filename"]
/// F["filename"]C
/// N - suppress
/// </summary>
/// <param name="sw">
///
/// </param>
/// <param name="text">
/// One of above forms.
/// </param>
/// <returns></returns>
private DisplaySummaryOptions ParseDisplaySummaryOptions(string switchValue) {
Debug.Assert(switchValue != null && switchValue.Length > 0);
if (switchValue.ToLower().StartsWith("n")) {
if (switchValue.Length > 1)
throw new ArgumentException(switchValue);
return new DisplaySummaryOptions(false);
}
bool toConsole = false;
bool toFile = false;
string filename = string.Empty;
StringBuilder sb = new StringBuilder(switchValue);
int startOfFilename = switchValue.IndexOf("\"");
if (startOfFilename > -1) {
int endOfFilename = switchValue.IndexOf("\"", startOfFilename + 1);
// must not be two consequetive enclosing qoutes
if (endOfFilename == startOfFilename + 1) {
throw new FormatException(FilenameEmpty);
}
// must be exactly two enclosing qoutes
if (endOfFilename == -1 || switchValue.LastIndexOf("\"") != endOfFilename) {
throw new FormatException(string.Format(FilenameNotEnclosedByQuotes, switchValue.Substring(startOfFilename)));
}
// filename must be preceeded by 'f'
if (startOfFilename == 0 || switchValue.Substring(startOfFilename - 1, 1).ToLower() != "f") {
throw new FormatException(string.Format(FilenameMustBePreceededByF, switchValue));
}
filename = switchValue.Substring(startOfFilename + 1, endOfFilename - startOfFilename - 1);
sb.Remove(startOfFilename, endOfFilename - startOfFilename + 1);
}
int n = sb.ToString().ToLower().IndexOf("f");
if (n > -1) {
toFile = true;
sb.Remove(n, 1);
}
n = sb.ToString().ToLower().IndexOf("c");
if (n > -1) {
toConsole = true;
sb.Remove(n, 1);
}
if (sb.Length > 0) {
throw new ArgumentException(sb.ToString());
}
return new DisplaySummaryOptions(toConsole, toFile, filename);
}
/// <summary>
/// Parses SourceSafe user options. Allowed forms (all preceeded by '/u':'):
/// [empty] - username and password will be prompted for
/// username - only username is provided, password is prompted for
/// username, - username, empty password
/// username,password - username and password
/// </summary>
/// <param name="switchValue">
/// Value to parse.
/// </param>
/// <returns>
/// <c>SourceSafeUserOptions</c> object initialized with provided
/// switch value(s).
/// </returns>
private SourceSafeUserOptions ParseSourceSafeOptions(string switchValue) {
Debug.Assert(switchValue != null && switchValue.Length > 0);
string[] splitNamePswd = switchValue.Split(',');
switch (splitNamePswd.Length) {
case 1:
// if only username provided
return new SourceSafeUserOptions(splitNamePswd[0]);
case 2:
// if username and password provided
return new SourceSafeUserOptions(splitNamePswd[0], splitNamePswd[1]);
}
throw new ArgumentException(string.Format(InvalidSwitchValue, switchValue));
}
/// <summary>
///
/// </summary>
/// <param name="sw"></param>
/// <param name="textToParse"></param>
private bool ParseCheckProjectsExistance(string switchValue) {
Debug.Assert(switchValue != null && switchValue.Length > 0);
switch (switchValue.ToLower()) {
case "e":
return true;
case "w":
return false;
default:
throw new ArgumentException(string.Format(InvalidSwitchValue, switchValue));
}
}
#endregion // Private methods
#region Private fields
private string m_solutionFilename;
private string m_newVersion;
private bool m_startGui;
private bool m_applyToAllProjects;
private AssemblyVersionType m_applyToTypes;
private ProjectsSynchronization m_projectsSynchronization;
private ProjectsNameList m_projectsAllowedForVersionModification;
private ProjectsNameList m_projectsToExclude;
private ProjectsNameList m_projectsToForce;
private DisplaySummaryOptions m_displaySummary;
private SourceSafeUserOptions m_sourceSafeUserOptions;
private bool m_checkProjectsExistance;
private readonly CommandLineSwitchesTable CommandLineSwitches;
#endregion // Private fields
#region String constants
private const string FileNotFound = "File not found: \'{0}\'";
private const string TooManyArguments = "Too many arguments provided: \'{0}\'";
private const string UnknownSwitch = "Unknown command line switch: \'{0}\'";
private const string ErrorInSwitch = "Error in switch: \'{0}\': {1}";
private const string NotEnclosedByQuotes = "List element \'{1}\' not enclosed by quotes on both sides.";
private const string FilenameNotEnclosedByQuotes = "Filename \'{0}\' not enclosed by quotes correctly.";
private const string DuplicateSwitch = "Switch \'{0}\' cannot appear multiple times.";
private const string SwitchHasNoValue = "No value assigned to switch \'{0}\'.";
private const string InvalidSwitchFormat = "Switch \'{0}\' has invalid format: {1}";
private const string InvalidSwitchValue = "Switch \'{0}\' is assigned invalid value \'{1}\'.";
//private const string ValueAlreadyAssigned = "The same value \'{0}\' already assigned.";
private const string AsteriskValueMustbeAlone = "\'*\' must not be used with any additional value.";
private const string FilenameMustBePreceededByF = "Filename \'{0}\' must be preceeded by 'f' character.";
private const string FilenameEmpty = "Filename must not be empty string.";
private const string ProjectNameAlreadySpecified = "Project name \'{0}\' listed more than once.";
private const string VersionFlagAlreadySet = "Flag for \'{0}\' set more than once.";
#endregion // String constants
#region Static methods
public static void OuputDescription(string executableName) {
CommandLineSwitchesTable.OutputDescription(executableName);
}
#endregion // Static methods
}
}