public static IsNullOrWhiteSpace ( string value ) : bool | ||
value | string | /// The string value to check. /// |
리턴 | bool |
/// <summary> /// Initializes a new instance of the <see cref="ConfigurationEntry"/> class. /// </summary> /// <param name="section"> /// The section of the configuration entry, used to group configuration entries together. /// </param> /// <param name="name"> /// The name of the configuration entry. /// </param> /// <param name="value"> /// The value of the configuration entry. /// </param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="section"/> is <c>null</c> or empty.</para> /// <para>- or -</para> /// <para><paramref name="name"/> is <c>null</c> or empty.</para> /// <para>- or -</para> /// <para><paramref name="value"/> is <c>null</c>.</para> /// </exception> public ConfigurationEntry(string section, string name, string value) { if (StringEx.IsNullOrWhiteSpace(section)) { throw new ArgumentNullException("section"); } if (StringEx.IsNullOrWhiteSpace(name)) { throw new ArgumentNullException("name"); } if (value == null) { throw new ArgumentNullException("value"); } _Section = section; _Name = name; _Value = value; }
/// <summary> /// Initializes a new instance of the <see cref="Annotation"/> class. /// </summary> /// <param name="lineNumber"> /// The line number for this <see cref="Annotation"/>. /// </param> /// <param name="revisionNumber"> /// The revision number of this <see cref="Annotation"/> /// </param> /// <param name="line"> /// The line that was annotated. /// </param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="line"/> is <c>null</c> or empty.</para> /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <para><paramref name="lineNumber"/> cannot be negative.</para> /// <para>- or -</para> /// <para><paramref name="revisionNumber"/> cannot be negative.</para> /// </exception> public Annotation(int lineNumber, int revisionNumber, string line) { if (StringEx.IsNullOrWhiteSpace(line)) { throw new ArgumentNullException("line"); } if (lineNumber < 0) { throw new ArgumentOutOfRangeException("lineNumber", lineNumber, "lineNumber cannot be negative"); } if (revisionNumber < 0) { throw new ArgumentOutOfRangeException("revisionNumber", revisionNumber, "revisionNumber cannot be negative"); } _LineNumber = lineNumber; _RevisionNumber = revisionNumber; _Line = line; }
/// <summary> /// This method should parse and store the appropriate execution result output /// according to the type of data the command line client would return for /// the command. /// </summary> /// <param name="exitCode"> /// The exit code from executing the command line client. /// </param> /// <param name="standardOutput"> /// The standard output from executing the command line client. /// </param> /// <exception cref="MercurialResultParsingException"> /// <para><paramref name="standardOutput"/> contains output with invalid/unknown format.</para> /// </exception> protected override void ParseStandardOutputForResults(int exitCode, string standardOutput) { string[] lines = OutputParsingUtilities.SplitIntoLines(standardOutput); var re = new Regex(@"^(?<name>.*)\s+(?<revno>-?\d+):[a-f0-9]+(\s+\(inactive\))?$", RegexOptions.IgnoreCase); var branchHeads = new List <BranchHead>(); foreach (Match ma in lines.Where(l => !StringEx.IsNullOrWhiteSpace(l)).Select(line => re.Match(line))) { if (!ma.Success) { throw new MercurialResultParsingException(exitCode, "Unable to parse output from the branches command", standardOutput); } branchHeads.Add(new BranchHead( int.Parse(ma.Groups["revno"].Value, CultureInfo.InvariantCulture), ma.Groups["name"].Value.Trim())); } Result = branchHeads.OrderBy(b => b.Name).ToArray(); }
/// <summary> /// Parses the standard output for results. /// </summary> /// <param name="exitCode">The exit code.</param> /// <param name="standardOutput">The standard output.</param> /// <exception cref="InvalidOperationException"> /// <para>Status does not yet support the Added sub-state to show where the file was added from.</para> /// <para>- or -</para> /// <para>An unknown status character was detected in the command output.</para> /// </exception> protected override void ParseStandardOutputForResults(int exitCode, string standardOutput) { base.ParseStandardOutputForResults(exitCode, standardOutput); var result = new List <FileStatus>(); var re = new Regex(@"^(?<status>[MARC!?I ])\s+(?<path>.*)$"); var statusEntries = from line in standardOutput.Split('\n', '\r') where !StringEx.IsNullOrWhiteSpace(line) let ma = re.Match(line) where ma.Success select new { status = ma.Groups["status"].Value[0], path = ma.Groups["path"].Value }; foreach (var entry in statusEntries) { FileState state; if (_FileStateCodes.TryGetValue(entry.status, out state)) { result.Add(new FileStatus(state, entry.path)); } else { if (entry.status == ' ') { throw new InvalidOperationException("Status does not yet support the Added sub-state to show where the file was added from"); } throw new InvalidOperationException( string.Format( CultureInfo.InvariantCulture, "Unknown status code reported by Mercurial: '{0}', I do not know how to handle that", entry.status)); } } Result = result; }
/// <summary> /// Lazily extract all the <logentry>...</logentry> xml pieces /// from the changeset xml log. /// </summary> /// <param name="xml"> /// The xml to extract the log entry xml pieces from. /// </param> /// <returns> /// A collection of strings containing xml, one string per /// <logentry>...</logentry>. /// </returns> private static IEnumerable <string> LazyExtractChangesetXmlPieces(string xml) { if (StringEx.IsNullOrWhiteSpace(xml)) { yield break; } using (var reader = new StringReader(xml)) { string line = reader.ReadLine(); if (line == null) { throw new InvalidOperationException("Invalid XML content"); } if (line.StartsWith("<?xml ")) { line = reader.ReadLine(); } if (line != "<log>") { throw new InvalidOperationException("Invalid XML content"); } var entryXml = new StringBuilder(); while ((line = reader.ReadLine()) != null) { if (line == "</log>") { yield break; } entryXml.AppendLine(line); if (line == "</logentry>") { yield return(entryXml.ToString()); entryXml.Length = 0; } } } }
/// <summary> /// Gets the sequence of arguments to pass to the command line client. This might write out a temporary file on disk, /// so be sure to call <see cref="Cleanup"/> when the command has completed execution. /// </summary> /// <returns> /// A collection of arguments to pass to the command line client. /// </returns> public string[] GetArguments() { var arguments = (from argument in _Collection where !StringEx.IsNullOrWhiteSpace(argument) select argument.Trim()).ToArray(); if (arguments.Length == 0) { return(arguments); } if (ClientExecutable.CurrentVersion < new Version(1, 8)) { return(arguments); } _ListFileName = Path.GetTempFileName(); File.WriteAllText(_ListFileName, string.Join(Environment.NewLine, arguments), _ListFileEncoding); return(new[] { string.Format(CultureInfo.InvariantCulture, "\"listfile:{0}\"", _ListFileName) }); }
/// <summary> /// Executes the given <see cref="IMercurialCommand"/> command against /// the Mercurial repository. /// </summary> /// <param name="repositoryPath"> /// The root path of the repository to execute the command in. /// </param> /// <param name="command"> /// The <see cref="IMercurialCommand"/> command to execute. /// </param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="repositoryPath"/> is <c>null</c>.</para> /// <para>- or -</para> /// <para><paramref name="command"/> is <c>null</c>.</para> /// </exception> /// <exception cref="MercurialException"> /// HG did not complete within the allotted time. /// </exception> public static void Execute(string repositoryPath, IMercurialCommand command) { if (StringEx.IsNullOrWhiteSpace(repositoryPath)) { throw new ArgumentNullException("repositoryPath"); } if (command == null) { throw new ArgumentNullException("command"); } ClientExecutable.LazyInitialize(); var specialArguments = (IEnumerable <string>) new[] { "--noninteractive", "--encoding", ClientExecutable.TextEncodingName, }; var environmentVariables = new[] { new KeyValuePair <string, string>("LANGUAGE", "EN"), new KeyValuePair <string, string>("HGENCODING", "cp1252"), }; CommandProcessor.Execute(repositoryPath, ClientExecutable.ClientPath, command, environmentVariables, specialArguments); MercurialVersionBase.Current.WaitForLocksToDissipate(repositoryPath); }
/// <summary> /// Executes the given <see cref="IMercurialCommand"/> command against /// the Mercurial repository. /// </summary> /// <param name="command"> /// The <see cref="IMercurialCommand"/> command to execute. /// </param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="command"/> is <c>null</c>.</para> /// </exception> /// <exception cref="MercurialException"> /// HG did not complete within the allotted time. /// </exception> public void Execute(IMercurialCommand command) { if (command == null) { throw new ArgumentNullException("command"); } if (_Process == null) { StartPersistentMercurialClient(); } command.Validate(); command.Before(); IEnumerable <string> arguments = new[] { command.Command, "--noninteractive", "--encoding", ClientExecutable.TextEncodingName, }; arguments = arguments.Concat(command.Arguments.Where(a => !StringEx.IsNullOrWhiteSpace(a))); arguments = arguments.Concat(command.AdditionalArguments.Where(a => !StringEx.IsNullOrWhiteSpace(a))); var commandParts = arguments.ToArray(); string commandEncoded = string.Join("\0", commandParts.Select(p => p.Trim('"')).ToArray()); int length = commandEncoded.Length; var commandBuffer = new StringBuilder(); commandBuffer.Append("runcommand\n"); commandBuffer.Append((char)((length >> 24) & 0xff)); commandBuffer.Append((char)((length >> 16) & 0xff)); commandBuffer.Append((char)((length >> 8) & 0xff)); commandBuffer.Append((char)(length & 0xff)); commandBuffer.Append(commandEncoded); string commandArguments = null; if (command.Observer != null) { commandArguments = string.Join(" ", commandParts.Skip(1).ToArray()); command.Observer.Executing(command.Command, commandArguments); } byte[] buffer = ClientExecutable.TextEncoding.GetBytes(commandBuffer.ToString()); foreach (byte b in buffer) { _Process.StandardInput.BaseStream.WriteByte(b); _Process.StandardInput.BaseStream.Flush(); } string standardOutput; string standardError; int exitCode; if (CommandServerOutputDecoder.GetOutput(_Process.StandardOutput, out standardOutput, out standardError, out exitCode)) { if (command.Observer != null) { using (var lineReader = new StringReader(standardOutput)) { string line; while ((line = lineReader.ReadLine()) != null) { command.Observer.Output(line); } } using (var lineReader = new StringReader(standardError)) { string line; while ((line = lineReader.ReadLine()) != null) { command.Observer.ErrorOutput(line); } } command.Observer.Executed(command.Command, commandArguments, exitCode, standardOutput, standardError); } command.After(exitCode, standardOutput, standardError); return; } StopPersistentMercurialClient(); throw new MercurialExecutionException("Unable to decode output from executing command, spinning down persistent client"); }
/// <summary> /// Executes the given <see cref="IMercurialCommand"/> command against /// the Mercurial repository. /// </summary> /// <param name="command"> /// The <see cref="IMercurialCommand"/> command to execute. /// </param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="command"/> is <c>null</c>.</para> /// </exception> /// <exception cref="MercurialException"> /// HG did not complete within the allotted time. /// </exception> public void Execute(IMercurialCommand command) { if (command == null) { throw new ArgumentNullException("command"); } if (_Process == null) { StartPersistentMercurialClient(); } command.Validate(); command.Before(); IEnumerable <string> arguments = new[] { command.Command, "--noninteractive", }; arguments = arguments.Concat(command.Arguments.Where(a => !StringEx.IsNullOrWhiteSpace(a))); arguments = arguments.Concat(command.AdditionalArguments.Where(a => !StringEx.IsNullOrWhiteSpace(a))); var commandParts = arguments.ToArray(); string commandEncoded = string.Join("\0", commandParts.Select(p => p.Trim('"')).ToArray()); int length = commandEncoded.Length; var commandBuffer = new StringBuilder(); commandBuffer.Append("runcommand\n"); commandBuffer.Append((char)((length >> 24) & 0xff)); commandBuffer.Append((char)((length >> 16) & 0xff)); commandBuffer.Append((char)((length >> 8) & 0xff)); commandBuffer.Append((char)(length & 0xff)); commandBuffer.Append(commandEncoded); string commandArguments = null; if (command.Observer != null) { commandArguments = string.Join(" ", commandParts.Skip(1).ToArray()); command.Observer.Executing(command.Command, commandArguments); } MemoryStream output = new MemoryStream(); MemoryStream error = new MemoryStream(); var outputs = new Dictionary <CommandChannel, Stream>() { { CommandChannel.Output, output }, { CommandChannel.Error, error }, }; var _codec = ClientExecutable.GetMainEncoding(); int resultCode = RunCommand(commandParts, outputs, null); var result = new CommandResult(_codec.GetString(output.GetBuffer(), 0, (int)output.Length), _codec.GetString(error.GetBuffer(), 0, (int)error.Length), resultCode); if (resultCode == 0 || !string.IsNullOrEmpty(result.Output)) { if (command.Observer != null) { command.Observer.Output(result.Output); command.Observer.ErrorOutput(result.Error); command.Observer.Executed(command.Command, commandArguments, resultCode, result.Output, result.Error); } command.After(resultCode, result.Output, result.Error); return; } StopPersistentMercurialClient(); throw new MercurialExecutionException( string.IsNullOrEmpty(result.Error) ? "Unable to decode output from executing command, spinning down persistent client" : result.Error); }
/// <summary> /// Initializes a new instance of the <see cref="RevSpec"/> class. /// </summary> /// <param name="value"> /// The value of this <see cref="RevSpec"/> value, can be both a hash and an expression. /// </param> public RevSpec(string value) { Debug.Assert(!StringEx.IsNullOrWhiteSpace(value), "value cannot be null or empty here"); _Value = value.Trim(); }
/// <summary> /// Executes the given executable to process the given command. /// </summary> /// <param name="workingDirectory"> /// The working directory while executing the command. /// </param> /// <param name="executable"> /// The full path to and name of the executable to execute. /// </param> /// <param name="command"> /// The options to the executable. /// </param> /// <param name="environmentVariables"> /// An array of <see cref="KeyValuePair{TKey,TValue}"/> objects, containing environment variable /// overrides to use while executing the executable. /// </param> /// <param name="specialArguments"> /// Any special arguments to pass to the executable, not defined by the <paramref name="command"/> /// object, typically common arguments that should always be passed to the executable. /// </param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="workingDirectory"/> is <c>null</c> or empty.</para> /// <para>- or -</para> /// <para><paramref name="executable"/> is <c>null</c> or empty.</para> /// <para>- or -</para> /// <para><paramref name="command"/> is <c>null</c>.</para> /// <para>- or -</para> /// <para><paramref name="environmentVariables"/> is <c>null</c>.</para> /// <para>- or -</para> /// <para><paramref name="specialArguments"/> is <c>null</c>.</para> /// </exception> /// <exception cref="MercurialException"> /// <para>The executable did not finish in the allotted time.</para> /// </exception> public static void Execute( string workingDirectory, string executable, ICommand command, KeyValuePair <string, string>[] environmentVariables, IEnumerable <string> specialArguments) { if (StringEx.IsNullOrWhiteSpace(workingDirectory)) { throw new ArgumentNullException("workingDirectory"); } if (StringEx.IsNullOrWhiteSpace(executable)) { throw new ArgumentNullException("executable"); } if (command == null) { throw new ArgumentNullException("command"); } if (environmentVariables == null) { throw new ArgumentNullException("environmentVariables"); } if (specialArguments == null) { throw new ArgumentNullException("specialArguments"); } command.Validate(); command.Before(); IEnumerable <string> arguments = specialArguments; arguments = arguments.Concat(command.Arguments.Where(a => !StringEx.IsNullOrWhiteSpace(a))); arguments = arguments.Concat(command.AdditionalArguments.Where(a => !StringEx.IsNullOrWhiteSpace(a))); string argumentsString = string.Join(" ", arguments.ToArray()); var psi = new ProcessStartInfo { FileName = executable, WorkingDirectory = workingDirectory, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, ErrorDialog = false, Arguments = command.Command + " " + argumentsString, }; foreach (var kvp in environmentVariables) { psi.EnvironmentVariables[kvp.Key] = kvp.Value; } ClientExecutable.LazyInitialize(); psi.StandardErrorEncoding = ClientExecutable.GetMainEncoding(); psi.StandardOutputEncoding = ClientExecutable.GetMainEncoding(); if (command.Observer != null) { command.Observer.Executing(command.Command, argumentsString); } Process process = Process.Start(psi); try { Func <StreamReader, Action <string>, string> reader; if (command.Observer != null) { reader = delegate(StreamReader streamReader, Action <string> logToObserver) { var output = new StringBuilder(); string line; while ((line = streamReader.ReadLine()) != null) { logToObserver(line); if (output.Length > 0) { output.Append(Environment.NewLine); } output.Append(line); } return(output.ToString()); }; } else { reader = (StreamReader streamReader, Action <string> logToObserver) => streamReader.ReadToEnd(); } IAsyncResult outputReader = reader.BeginInvoke(process.StandardOutput, line => command.Observer.Output(line), null, null); IAsyncResult errorReader = reader.BeginInvoke(process.StandardError, line => command.Observer.ErrorOutput(line), null, null); int timeout = Timeout.Infinite; if (command.Timeout > 0) { timeout = 1000 * command.Timeout; } if (!process.WaitForExit(timeout)) { if (command.Observer != null) { command.Observer.Executed(psi.FileName, psi.Arguments, 0, string.Empty, string.Empty); } throw new MercurialException("The executable did not complete within the allotted time"); } string standardOutput = reader.EndInvoke(outputReader); string errorOutput = reader.EndInvoke(errorReader); if (command.Observer != null) { command.Observer.Executed(command.Command, argumentsString, process.ExitCode, standardOutput, errorOutput); } command.After(process.ExitCode, standardOutput, errorOutput); } finally { process.Dispose(); } }
/// <summary> /// Parse the given XML lazily and return a collection of <see cref="Changeset"/> /// objects for the information contained in it, in the order the changesets /// appear in the xml. /// </summary> /// <param name="xml"> /// The XML to parse. /// </param> /// <returns> /// A collection of <see cref="Changeset"/> objects. /// </returns> /// <exception cref="InvalidOperationException"> /// <para>An unknown path action character was detected in the log output.</para> /// <para>- or -</para> /// <para>The XML content was not legal according to the expected format.</para> /// </exception> public static IEnumerable <Changeset> LazyParse(string xml) { if (StringEx.IsNullOrWhiteSpace(xml)) { yield break; } var serializer = new XmlSerializer(typeof(LogEntryNode)); foreach (string entryXml in LazyExtractChangesetXmlPieces(xml)) { var entry = (LogEntryNode)serializer.Deserialize(new StringReader(entryXml)); var changeset = new Changeset { Timestamp = entry.Timestamp, AuthorName = (entry.Author ?? new LogEntryAuthorNode()).Name, AuthorEmailAddress = (entry.Author ?? new LogEntryAuthorNode()).Email, CommitMessage = entry.CommitMessage ?? string.Empty, Branch = entry.Branch ?? "default", Hash = entry.Hash, RevisionNumber = entry.Revision, Revision = RevSpec.Single(entry.Hash), Tags = entry.Tags.Select(t => t.Name).ToArray(), }; switch (entry.Parents.Count) { case 2: changeset.RightParentHash = entry.Parents[1].Hash; changeset.RightParentRevision = entry.Parents[1].Revision; goto case 1; case 1: changeset.LeftParentHash = entry.Parents[0].Hash; changeset.LeftParentRevision = entry.Parents[0].Revision; break; case 0: changeset.LeftParentRevision = changeset.RevisionNumber - 1; break; } foreach (LogEntryPathNode action in entry.PathActions) { var pathAction = new ChangesetPathAction { Path = action.Path, }; switch (action.Action) { case "M": pathAction.Action = ChangesetPathActionType.Modify; break; case "A": pathAction.Action = ChangesetPathActionType.Add; LogEntryCopyNode copySource = entry.Copies.Where(c => c.Destination == action.Path).FirstOrDefault(); if (copySource != null) { pathAction.Source = copySource.Source; } break; case "R": pathAction.Action = ChangesetPathActionType.Remove; break; default: throw new InvalidOperationException("Unknown path action: " + action.Action); } changeset.PathActions.Add(pathAction); } yield return(changeset); } }