Exemplo n.º 1
0
        /// <summary>
        /// Patches the file and injects the revision data.
        /// </summary>
        /// <param name="fallbackFormat">The fallback format if none is defined in the file.</param>
        /// <param name="data">The revision data to use for resolving formats.</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>
        public void PatchFile(string fallbackFormat, RevisionData data, bool simpleAttributes, bool informationalAttribute, bool revOnly)
        {
            Program.ShowDebugMessage("Patching file \"" + fileName + "\"…");
            string backupFileName = CreateBackup();

            // Read the backup file. If the backup was created earlier, it still contains the source
            // file while the regular file may have been resolved but not restored before. By
            // reading the former source file, we get the correct result and can heal the situation
            // with the next restore run.
            ReadFileLines(backupFileName);

            // Find the revision format for this file
            revisionFormat = FindRevisionFormat();
            if (revisionFormat == null)
            {
                // Nothing defined in this file. Use whatever was specified on the command line or
                // found in any of the projects in the solution.
                revisionFormat = fallbackFormat;
            }
            else
            {
                Program.ShowDebugMessage("The file defines a revision format: " + revisionFormat);
            }
            if (revisionFormat == null)
            {
                // If we don't have a revision format, there's nothing to replace in this file.
                return;
            }
            var rf = new RevisionFormat();

            rf.RevisionData = data;

            // Process all lines in the file
            ResolveAllLines(rf, simpleAttributes, informationalAttribute, revOnly);

            // Write back all lines to the file
            WriteFileLines();
        }
Exemplo n.º 2
0
        /// <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));
            }
        }
Exemplo n.º 3
0
        /// <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>
		/// Patches the file and injects the revision data.
		/// </summary>
		/// <param name="fallbackFormat">The fallback format if none is defined in the file.</param>
		/// <param name="data">The revision data to use for resolving formats.</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>
		public void PatchFile(string fallbackFormat, RevisionData data, bool simpleAttributes, bool informationalAttribute, bool revOnly, bool copyrightAttribute)
		{
			Program.ShowDebugMessage("Patching file \"" + fileName + "\"…");
			string backupFileName = CreateBackup();

			// Read the backup file. If the backup was created earlier, it still contains the source
			// file while the regular file may have been resolved but not restored before. By
			// reading the former source file, we get the correct result and can heal the situation
			// with the next restore run.
			ReadFileLines(backupFileName);

			// Find the revision format for this file
			revisionFormat = FindRevisionFormat();
			if (revisionFormat == null)
			{
				// Nothing defined in this file. Use whatever was specified on the command line or
				// found in any of the projects in the solution.
				revisionFormat = fallbackFormat;
			}
			else
			{
				Program.ShowDebugMessage("The file defines a revision format: " + revisionFormat);
			}
			if (revisionFormat == null)
			{
				// If we don't have a revision format, there's nothing to replace in this file.
				return;
			}
			var rf = new RevisionFormat();
			rf.RevisionData = data;

			// Process all lines in the file
			ResolveAllLines(rf, simpleAttributes, informationalAttribute, revOnly, copyrightAttribute);

			// Write back all lines to the file
			WriteFileLines();
		}
		/// <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 + "\".");
					}
				}
			}
		}
Exemplo n.º 6
0
        /// <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));
            }
        }