/// <summary> /// Wrapped main program, uses <see cref="ConsoleException"/> as return code in case of /// error and does not wait at the end. /// </summary> private static void MainWrapper() { CommandLineHelper cmdLine = new CommandLineHelper(); var showHelpOption = cmdLine.RegisterOption("help").Alias("h", "?"); var showVersionOption = cmdLine.RegisterOption("version").Alias("ver"); var debugOption = cmdLine.RegisterOption("debug"); var patchAssemblyInfoOption = cmdLine.RegisterOption("patch"); var restorePatchedFilesOption = cmdLine.RegisterOption("restore"); var simpleAttributeOption = cmdLine.RegisterOption("simple"); var informationalAttributeOption = cmdLine.RegisterOption("info"); var noCopyrightAttributeOption = cmdLine.RegisterOption("nocopyright"); var echoOption = cmdLine.RegisterOption("echo"); var formatOption = cmdLine.RegisterOption("format", 1); var revisionOnlyOption = cmdLine.RegisterOption("revonly"); var requireVcsOption = cmdLine.RegisterOption("require", 1); var rejectModifiedOption = cmdLine.RegisterOption("rejectmod").Alias("rejectmodified"); var rejectMixedOption = cmdLine.RegisterOption("rejectmix").Alias("rejectmixed"); var tagMatchOption = cmdLine.RegisterOption("tagmatch", 1); var removeTagVOption = cmdLine.RegisterOption("removetagv"); var multiProjectOption = cmdLine.RegisterOption("multi"); var scanRootOption = cmdLine.RegisterOption("root"); var decodeRevisionOption = cmdLine.RegisterOption("decode", 1); var predictRevisionsOption = cmdLine.RegisterOption("predict"); try { //cmdLine.ReadArgs(Environment.CommandLine, true); // Alternative split method, should have the same result cmdLine.Parse(); showDebugOutput = debugOption.IsSet; if (showDebugOutput) { ShowDebugMessage( "Command line: " + Environment.GetCommandLineArgs() .Select(s => "[" + s + "]") .Aggregate((a, b) => a + " " + b)); } } catch (Exception ex) { throw new ConsoleException(ex.Message, ExitCodes.CmdLineError); } // Handle simple text output options if (showHelpOption.IsSet) { ShowHelp(); return; } if (showVersionOption.IsSet) { ShowVersion(); return; } // Check for environment variable from PowerShell build framework. // If psbuild has set this variable, it is using .NET Revision Tool itself in // multi-project mode and pre/postbuild actions in individual projects should not do // anything on their own. if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SuppressNetRevisionTool"))) { ShowDebugMessage("SuppressNetRevisionTool environment variable is set. Quitting…"); return; } // Find all directories string path = GetWorkPath(cmdLine); string[] projectDirs = null; if (multiProjectOption.IsSet) { // Read solution file and collect all projects projectDirs = GetProjectsFromSolution(path); // From now on, work with the solution directory as default path to get the revision of if (Path.GetExtension(path).ToLowerInvariant() == ".sln") { path = Path.GetDirectoryName(path); } } else { if (!Directory.Exists(path)) { throw new ConsoleException("The specified project directory does not exist.", ExitCodes.FileNotFound); } projectDirs = new[] { path }; } // Restoring doesn't need more info, do it now if (restorePatchedFilesOption.IsSet) { // Restore AssemblyInfo file(s) foreach (string projectDir in projectDirs) { var aih = new AssemblyInfoHelper(projectDir, true); aih.RestoreFile(); } return; } // Setup public data if (tagMatchOption.IsSet) { TagMatch = tagMatchOption.Value; } RemoveTagV = removeTagVOption.IsSet; // Analyse working directory RevisionData data = ProcessDirectory(path, scanRootOption.IsSet, requireVcsOption.Value); data.Normalize(); // Check for required VCS if (requireVcsOption.IsSet) { if (data.VcsProvider == null || !data.VcsProvider.Name.Equals(requireVcsOption.Value, StringComparison.OrdinalIgnoreCase)) { throw new ConsoleException("Required VCS \"" + requireVcsOption.Value + "\" not present.", ExitCodes.RequiredVcs); } } // Check for reject modifications/mixed revisions if (rejectModifiedOption.IsSet && data.IsModified) { throw new ConsoleException("The working directory contains uncommitted modifications.", ExitCodes.RejectModified); } if (rejectMixedOption.IsSet && data.IsMixed) { throw new ConsoleException("The working directory contains mixed revisions.", ExitCodes.RejectMixed); } // Determine revision ID format, in case we need one here string format = null; if (formatOption.IsSet && !string.IsNullOrWhiteSpace(formatOption.Value)) { // Take from command-line option format = formatOption.Value; ShowDebugMessage("Format specified: " + format); } else { // None or empty specified. Search in AssemblyInfo file(s) in the project(s) ShowDebugMessage("No format specified, searching AssemblyInfo source file."); AssemblyInfoHelper aih = null; foreach (string projectDir in projectDirs) { aih = new AssemblyInfoHelper(projectDir, false); if (aih.FileExists) { format = aih.GetRevisionFormat(); if (format != null) { if (projectDirs.Length > 1) { ShowDebugMessage("Found format in project \"" + projectDir + "\"."); } break; } } else { ShowDebugMessage(" AssemblyInfo source file not found.", 2); } } if (format != null) { ShowDebugMessage("Found format: " + format); } } if (format == null) { if (data.RevisionNumber > 0) { ShowDebugMessage("No format available, using default format for revision number."); format = "{revnum}"; } else if (!string.IsNullOrEmpty(data.CommitHash) && !Regex.IsMatch(data.CommitHash, "^0+$")) { ShowDebugMessage("No format available, using default format for commit hash."); format = "{chash:8}"; } else { ShowDebugMessage("No format available, using empty format."); format = ""; } } if (decodeRevisionOption.IsSet) { // Decode specified revision ID RevisionFormat.ShowDecode(format, decodeRevisionOption.Value); } else if (predictRevisionsOption.IsSet) { // Predict next revision IDs RevisionFormat.PredictValue(format); } else if (patchAssemblyInfoOption.IsSet) { // Patch AssemblyInfo file(s) bool noAttrSet = !simpleAttributeOption.IsSet && !informationalAttributeOption.IsSet; bool simpleAttributes = simpleAttributeOption.IsSet || noAttrSet; bool informationalAttribute = informationalAttributeOption.IsSet || noAttrSet; foreach (string projectDir in projectDirs) { var aih = new AssemblyInfoHelper(projectDir, true); aih.PatchFile(format, data, simpleAttributes, informationalAttribute, revisionOnlyOption.IsSet, !noCopyrightAttributeOption.IsSet, echoOption.IsSet); } } else { // Just display revision ID var rf = new RevisionFormat(); rf.RevisionData = data; Console.WriteLine(rf.Resolve(format)); } }
/// <summary> /// Resolves all attributes in the file. /// </summary> /// <param name="rf">The revision format for the file.</param> /// <param name="simpleAttributes">Indicates whether simple version attributes are processed.</param> /// <param name="informationalAttribute">Indicates whether the AssemblyInformationalVersion attribute is processed.</param> /// <param name="revOnly">Indicates whether only the last number is replaced by the revision number.</param> /// <param name="copyrightAttribute">Indicates whether the copyright year is replaced.</param> private void ResolveAllLines(RevisionFormat rf, bool simpleAttributes, bool informationalAttribute, bool revOnly, bool copyrightAttribute) { // Preparing a truncated dotted-numeric version if we may need it string truncVersion = null; if (simpleAttributes && !revOnly) { string revisionId = rf.Resolve(revisionFormat); truncVersion = Regex.Replace(revisionId, @"[^0-9.].*$", "").TrimEnd('.'); if (!truncVersion.Contains(".")) throw new ConsoleException("Revision ID cannot be truncated to dotted-numeric: " + revisionId, ExitCodes.NoNumericVersion); Version version; if (!Version.TryParse(truncVersion, out version)) throw new ConsoleException("Revision ID cannot be truncated to dotted-numeric: " + revisionId, ExitCodes.NoNumericVersion); } // Checking the revision number if we may need it int revNum = rf.RevisionData.RevisionNumber; if (revOnly) { if (revNum == 0) { // No revision number available, try to use the format as a number string revisionId = rf.Resolve(revisionFormat); if (int.TryParse(revisionId, System.Globalization.NumberStyles.None, System.Globalization.CultureInfo.InvariantCulture, out revNum)) { Program.ShowDebugMessage("Using revision number " + revNum + " for /revonly from format.", 0); } } if (revNum == 0) { // Still nothing useful available Program.ShowDebugMessage("Revision number is 0. Did you really mean to use /revonly?", 2); } if (revNum > ushort.MaxValue) { throw new ConsoleException("Revision number " + revNum + " is greater than " + ushort.MaxValue + " and cannot be used here. Consider using the offset option.", ExitCodes.RevNumTooLarge); } } // Process all lines Match match; for (int i = 0; i < lines.Length; i++) { if (revOnly) { // Replace the fourth part of AssemblyVersion and AssemblyFileVersion with the // revision number. If less parts are currently specified, zeros are inserted. match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyVersion\s*\(\s*""[0-9]+)(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { lines[i] = match.Groups[1].Value + (match.Groups[2].Success ? match.Groups[2].Value : ".0") + (match.Groups[3].Success ? match.Groups[3].Value : ".0") + "." + revNum + match.Groups[5].Value; Program.ShowDebugMessage("Found AssemblyVersion attribute for revision number only.", 1); } match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyFileVersion\s*\(\s*""[0-9]+)(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { lines[i] = match.Groups[1].Value + (match.Groups[2].Success ? match.Groups[2].Value : ".0") + (match.Groups[3].Success ? match.Groups[3].Value : ".0") + "." + revNum + match.Groups[5].Value; Program.ShowDebugMessage("Found AssemblyFileVersion attribute for revision number only.", 1); } } if (simpleAttributes && !revOnly) { // Replace the entire version in AssemblyVersion and AssemblyFileVersion with // the truncated dotted-numeric version. match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyVersion\s*\(\s*"")(.*?)(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { lines[i] = match.Groups[1].Value + truncVersion + match.Groups[3].Value; Program.ShowDebugMessage("Found AssemblyVersion attribute.", 1); Program.ShowDebugMessage(" Replaced \"" + match.Groups[2].Value + "\" with \"" + truncVersion + "\"."); } match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyFileVersion\s*\(\s*"")(.*?)(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { lines[i] = match.Groups[1].Value + truncVersion + match.Groups[3].Value; Program.ShowDebugMessage("Found AssemblyFileVersion attribute.", 1); Program.ShowDebugMessage(" Replaced \"" + match.Groups[2].Value + "\" with \"" + truncVersion + "\"."); } } if (informationalAttribute && !revOnly) { // Replace the entire value of AssemblyInformationalVersion with the resolved // string of what was already there. This ignores the fallback format, should // one be given on the command line. match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyInformationalVersion\s*\(\s*"")(.*?)(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { string revisionId = rf.Resolve(match.Groups[2].Value); lines[i] = match.Groups[1].Value + revisionId + match.Groups[3].Value; Program.ShowDebugMessage("Found AssemblyInformationalVersion attribute.", 1); Program.ShowDebugMessage(" Replaced \"" + match.Groups[2].Value + "\" with \"" + revisionId + "\"."); } } if (copyrightAttribute) { // Replace the entire value of Copyright with the resolved string of what was // already there. match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyCopyright\s*\(\s*"")(.*?)(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { string copyrightText = rf.Resolve(match.Groups[2].Value); lines[i] = match.Groups[1].Value + copyrightText + match.Groups[3].Value; Program.ShowDebugMessage("Found AssemblyCopyright attribute.", 1); Program.ShowDebugMessage(" Replaced \"" + match.Groups[2].Value + "\" with \"" + copyrightText + "\"."); } } } }
/// <summary> /// Resolves all attributes in the file. /// </summary> /// <param name="rf">The revision format for the file.</param> /// <param name="simpleAttributes">Indicates whether simple version attributes are processed.</param> /// <param name="informationalAttribute">Indicates whether the AssemblyInformationalVersion attribute is processed.</param> /// <param name="revOnly">Indicates whether only the last number is replaced by the revision number.</param> private void ResolveAllLines(RevisionFormat rf, bool simpleAttributes, bool informationalAttribute, bool revOnly) { // Preparing a truncated dotted-numeric version if we may need it string truncVersion = null; if (simpleAttributes && !revOnly) { string revisionId = rf.Resolve(revisionFormat); truncVersion = Regex.Replace(revisionId, @"[^0-9.].*$", ""); if (!truncVersion.Contains(".")) { throw new ConsoleException("Revision ID cannot be truncated to dotted-numeric: " + revisionId, ExitCodes.NoNumericVersion); } Version version; if (!Version.TryParse(truncVersion, out version)) { throw new ConsoleException("Revision ID cannot be truncated to dotted-numeric: " + revisionId, ExitCodes.NoNumericVersion); } } // Checking the revision number if we may need it int revNum = rf.RevisionData.RevisionNumber; if (revOnly) { if (revNum == 0) { // No revision number available, try to use the format as a number string revisionId = rf.Resolve(revisionFormat); if (int.TryParse(revisionId, System.Globalization.NumberStyles.None, System.Globalization.CultureInfo.InvariantCulture, out revNum)) { Program.ShowDebugMessage("Using revision number " + revNum + " for /revonly from format.", 0); } } if (revNum == 0) { // Still nothing useful available Program.ShowDebugMessage("Revision number is 0. Did you really mean to use /revonly?", 2); } if (revNum > UInt16.MaxValue) { throw new ConsoleException("Revision number " + revNum + " is greater than " + UInt16.MaxValue + " and cannot be used here. Consider using the offset option.", ExitCodes.RevNumTooLarge); } } // Process all lines Match match; for (int i = 0; i < lines.Length; i++) { if (revOnly) { // Replace the fourth part of AssemblyVersion and AssemblyFileVersion with the // revision number. If less parts are currently specified, zeros are inserted. match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyVersion\s*\(\s*""[0-9]+)(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { lines[i] = match.Groups[1].Value + (match.Groups[2].Success ? match.Groups[2].Value : ".0") + (match.Groups[3].Success ? match.Groups[3].Value : ".0") + "." + revNum + match.Groups[5].Value; Program.ShowDebugMessage("Found AssemblyVersion attribute for revision number only.", 1); } match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyFileVersion\s*\(\s*""[0-9]+)(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { lines[i] = match.Groups[1].Value + (match.Groups[2].Success ? match.Groups[2].Value : ".0") + (match.Groups[3].Success ? match.Groups[3].Value : ".0") + "." + revNum + match.Groups[5].Value; Program.ShowDebugMessage("Found AssemblyFileVersion attribute for revision number only.", 1); } } if (simpleAttributes && !revOnly) { // Replace the entire version in AssemblyVersion and AssemblyFileVersion with // the truncated dotted-numeric version. match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyVersion\s*\(\s*"")(.*?)(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { lines[i] = match.Groups[1].Value + truncVersion + match.Groups[3].Value; Program.ShowDebugMessage("Found AssemblyVersion attribute.", 1); Program.ShowDebugMessage(" Replaced \"" + match.Groups[2].Value + "\" with \"" + truncVersion + "\"."); } match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyFileVersion\s*\(\s*"")(.*?)(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { lines[i] = match.Groups[1].Value + truncVersion + match.Groups[3].Value; Program.ShowDebugMessage("Found AssemblyFileVersion attribute.", 1); Program.ShowDebugMessage(" Replaced \"" + match.Groups[2].Value + "\" with \"" + truncVersion + "\"."); } } if (informationalAttribute && !revOnly) { // Replace the entire value of AssemblyInformationalVersion with the resolved // string of what was already there. This ignores the fallback format, should // one be given on the command line. match = Regex.Match( lines[i], @"^(\s*\" + attrStart + @"\s*assembly\s*:\s*AssemblyInformationalVersion\s*\(\s*"")(.*?)(""\s*\)\s*\" + attrEnd + @".*)$", RegexOptions.IgnoreCase); if (match.Success) { string revisionId = rf.Resolve(match.Groups[2].Value); lines[i] = match.Groups[1].Value + revisionId + match.Groups[3].Value; Program.ShowDebugMessage("Found AssemblyInformationalVersion attribute.", 1); Program.ShowDebugMessage(" Replaced \"" + match.Groups[2].Value + "\" with \"" + revisionId + "\"."); } } } }
/// <summary> /// Wrapped main program, uses <see cref="ConsoleException"/> as return code in case of /// error and does not wait at the end. /// </summary> private static void MainWrapper() { CommandLineHelper cmdLine = new CommandLineHelper(); var showHelpOption = cmdLine.RegisterOption("help").Alias("h", "?"); var showVersionOption = cmdLine.RegisterOption("version").Alias("ver"); var debugOption = cmdLine.RegisterOption("debug"); var patchAssemblyInfoOption = cmdLine.RegisterOption("patch"); var restorePatchedFilesOption = cmdLine.RegisterOption("restore"); var simpleAttributeOption = cmdLine.RegisterOption("simple"); var informationalAttributeOption = cmdLine.RegisterOption("info"); var allAttributesOption = cmdLine.RegisterOption("all"); var formatOption = cmdLine.RegisterOption("format", 1); var revisionOnlyOption = cmdLine.RegisterOption("revonly"); var requireVcsOption = cmdLine.RegisterOption("require", 1); var rejectModifiedOption = cmdLine.RegisterOption("rejectmod").Alias("rejectmodified"); var rejectMixedOption = cmdLine.RegisterOption("rejectmix").Alias("rejectmixed"); var multiProjectOption = cmdLine.RegisterOption("multi"); var scanRootOption = cmdLine.RegisterOption("root"); var decodeRevisionOption = cmdLine.RegisterOption("decode", 1); var predictRevisionsOption = cmdLine.RegisterOption("predict"); try { //cmdLine.ReadArgs(Environment.CommandLine, true); // Alternative split method, should have the same result cmdLine.Parse(); showDebugOutput = debugOption.IsSet; if (showDebugOutput) { ShowDebugMessage( "Command line: " + Environment.GetCommandLineArgs() .Select(s => "[" + s + "]") .Aggregate((a, b) => a + " " + b)); } } catch (Exception ex) { throw new ConsoleException(ex.Message, ExitCodes.CmdLineError); } // Handle simple text output options if (showHelpOption.IsSet) { ShowHelp(); return; } if (showVersionOption.IsSet) { ShowVersion(); return; } // Check for environment variable from PowerShell build framework. // If psbuild has set this variable, it is using NetRevisionTool itself in multi-project // mode and pre/postbuild actions in individual projects should not do anything on their // own. if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("SuppressNetRevisionTool"))) { ShowDebugMessage("SuppressNetRevisionTool environment variable is set. Quitting…"); return; } // Find all directories string path = GetWorkPath(cmdLine); string[] projectDirs = null; if (multiProjectOption.IsSet) { // Read solution file and collect all projects projectDirs = GetProjectsFromSolution(path); // From now on, work with the solution directory as default path to get the revision of if (Path.GetExtension(path).ToLowerInvariant() == ".sln") { path = Path.GetDirectoryName(path); } } else { if (!Directory.Exists(path)) throw new ConsoleException("The specified project directory does not exist.", ExitCodes.FileNotFound); projectDirs = new[] { path }; } // Restoring doesn't need more info, do it now if (restorePatchedFilesOption.IsSet) { // Restore AssemblyInfo file(s) foreach (string projectDir in projectDirs) { var aih = new AssemblyInfoHelper(projectDir, true); aih.RestoreFile(); } return; } // Analyse working directory RevisionData data = ProcessDirectory(path, scanRootOption.IsSet, requireVcsOption.Value); data.Normalize(); // Check for required VCS if (requireVcsOption.IsSet) { if (data.VcsProvider == null || !data.VcsProvider.Name.Equals(requireVcsOption.Value, StringComparison.OrdinalIgnoreCase)) { throw new ConsoleException("Required VCS \"" + requireVcsOption.Value + "\" not present.", ExitCodes.RequiredVcs); } } // Check for reject modifications/mixed revisions if (rejectModifiedOption.IsSet && data.IsModified) { throw new ConsoleException("The working directory contains uncommitted modifications.", ExitCodes.RejectModified); } if (rejectMixedOption.IsSet && data.IsMixed) { throw new ConsoleException("The working directory contains mixed revisions.", ExitCodes.RejectMixed); } // Determine revision ID format, in case we need one here string format = null; if (formatOption.IsSet && !string.IsNullOrWhiteSpace(formatOption.Value)) { // Take from command-line option format = formatOption.Value; ShowDebugMessage("Format specified: " + format); } else { // None or empty specified. Search in AssemblyInfo file(s) in the project(s) ShowDebugMessage("No format specified, searching AssemblyInfo source file."); AssemblyInfoHelper aih = null; foreach (string projectDir in projectDirs) { aih = new AssemblyInfoHelper(projectDir, false); if (aih.FileExists) { format = aih.GetRevisionFormat(); if (format != null) { if (projectDirs.Length > 1) { ShowDebugMessage("Found format in project \"" + projectDir + "\"."); } break; } } else { ShowDebugMessage(" AssemblyInfo source file not found.", 2); } } if (format != null) { ShowDebugMessage("Found format: " + format); } } if (format == null) { if (data.RevisionNumber > 0) { ShowDebugMessage("No format available, using default format for revision number."); format = "{revnum}"; } else if (!string.IsNullOrEmpty(data.CommitHash) && !Regex.IsMatch(data.CommitHash, "^0+$")) { ShowDebugMessage("No format available, using default format for commit hash."); format = "{chash:8}"; } else { ShowDebugMessage("No format available, using empty format."); format = ""; } } if (decodeRevisionOption.IsSet) { // Decode specified revision ID RevisionFormat.ShowDecode(format, decodeRevisionOption.Value); } else if (predictRevisionsOption.IsSet) { // Predict next revision IDs RevisionFormat.PredictValue(format); } else if (patchAssemblyInfoOption.IsSet) { // Patch AssemblyInfo file(s) bool noAttrSet = !simpleAttributeOption.IsSet && !informationalAttributeOption.IsSet; bool simpleAttributes = simpleAttributeOption.IsSet || noAttrSet; bool informationalAttribute = informationalAttributeOption.IsSet || noAttrSet; foreach (string projectDir in projectDirs) { var aih = new AssemblyInfoHelper(projectDir, true); aih.PatchFile(format, data, simpleAttributes, informationalAttribute, revisionOnlyOption.IsSet); } } else { // Just display revision ID var rf = new RevisionFormat(); rf.RevisionData = data; Console.WriteLine(rf.Resolve(format)); } }