Index: Tools/Google.Apis.Release/Repositories/Hg.cs =================================================================== rename from Tools/Google.Build.Utils/Repositories/Hg.cs rename to Tools/Google.Apis.Release/Repositories/Hg.cs --- a/Tools/Google.Build.Utils/Repositories/Hg.cs +++ b/Tools/Google.Apis.Release/Repositories/Hg.cs @@ -22,33 +22,26 @@ using System.Runtime.InteropServices; using System.Text.RegularExpressions; -using Google.Apis.Samples.Helper; +using Google.Apis.Utils; +using Google.Apis.Utils.Trace; -namespace Google.Build.Utils.Repositories +namespace Google.Apis.Release.Repositories { - /// - /// Mercurial interfacing class - /// + /// Mercurial repository interface class. public sealed class Hg : IDisposable { - /// - /// Name of the repository. - /// + static readonly TraceSource TraceSource = new TraceSource("Google.Apis"); + + /// Gets the name of the repository.summary> public string Name { get; private set; } - /// - /// The URI of the repositoty - /// + /// Gets the URI of the repository public Uri RepositoryUri { get; private set; } - /// - /// The local working directory. - /// + /// Gets the local working directory. public string WorkingDirectory { get; private set; } - /// - /// True if this working copy has pending changes. - /// + /// Gets indication if repository has pending changes. public bool HasUncommitedChanges { get @@ -58,9 +51,7 @@ } } - /// - /// True if there are unpulled, incoming changes. - /// + /// Gets indication if there are incoming changes. public bool HasIncomingChanges { get @@ -77,16 +68,14 @@ } } - /// - /// True if this working copy has unpushed changes. - /// + /// Gets indication if the working copy has un-pushed changes. public bool HasUnpushedChanges { get { try { - string[] changes = RunListeningHg("outgoing {0} {1}", "-l", "1"); + string[] changes = RunListeningHg(string.Format("outgoing {0} {1}", "-l", "1")); return changes.Length >= 4; } catch (ExternalException) @@ -99,12 +88,13 @@ } } - private Hg(Uri repositoryUri) - : this(repositoryUri, Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())) - { - - } - private Hg(Uri repositoryUri, string localDir) + /// + /// Constructs a new repository. It creates a new repository if the folder doesn't exists, otherwise it gets + /// the current status of the repository. + /// + /// The URI of this repository + /// The local directory which contains the repository files + public Hg(Uri repositoryUri, string localDir) { RepositoryUri = repositoryUri; WorkingDirectory = Path.GetFullPath(localDir); @@ -112,19 +102,18 @@ if (!Directory.Exists(WorkingDirectory)) { + TraceSource.TraceEvent(TraceEventType.Information, "[{0}] Fetching {1}", Name, repositoryUri); Directory.CreateDirectory(WorkingDirectory); - this.CloneFrom(repositoryUri); + RunHg(string.Format("clone {0} {1}", repositoryUri.ToString(), WorkingDirectory)); } else { - CommandLine.WriteAction("Using existing repository for " + Name + " at " + WorkingDirectory + " .."); + TraceSource.TraceEvent(TraceEventType.Information, "[{0}] Using an existing repository", Name); RunHg("status"); } } - /// - /// Commits the pending changes. - /// + /// Commits the pending changes. /// Description of the changes/the commit. /// Whether a commit was made/possible. public bool Commit(string message) @@ -136,54 +125,30 @@ RunHg("status -m -a -r"); - CommandLine.WriteAction("Commiting changes of " + Name + " .."); - RunHg("commit -m \"{0}\"", message); + TraceSource.TraceEvent(TraceEventType.Information, "[{0}] Committing changes", Name); + RunHg(string.Format("commit -m \"{0}\"", message)); return true; } - /// - /// Adds a tag to the last revision. - /// + /// Adds a tag to the last revision. /// The tag to add. /// - /// If set to true will overwrite existing labels of this name see "hg help tag" and its - /// --force parameter. + /// If set to true will overwrite existing labels of this name see "hg help tag" and its --force parameter. /// public void Tag(string tagName, bool force = false) { - CommandLine.WriteAction("Tagging " + Name + " with " + tagName + ".."); + TraceSource.TraceEvent(TraceEventType.Information, "[{0}] Tagging with {1}", Name, tagName); string options = (force ? "-f " : ""); - RunHg("tag {0}\"{1}\"", options, tagName); + RunHg(string.Format("tag {0}\"{1}\"", options, tagName)); } - /// - /// Adds all unversioned files to the current commit. - /// - public void AddUnversionedFiles() + /// Adds all unversioned files and remove all versioned files. + public void AddRemoveFiles() { - RunHg("add"); + RunHg("addremove"); } - /// - /// Marks all versioned files which have been deleted as removed. - /// - public void RemoveDeletedFiles() - { - var missingFiles = RunListeningHg("status -d") - .Where(l => l.StartsWith("! ")) - .Select(l => "\"" + l.Substring("! ".Length) + "\""); - - string files = String.Join(" ", missingFiles); - if (!string.IsNullOrEmpty(files)) - { - CommandLine.WriteAction("Removing files: " + files); - RunHg("remove {0}", files); - } - } - - /// - /// Pushes all commited changes to the server. - /// + /// Pushes all committed changes to the server. public void Push() { if (!HasUnpushedChanges) @@ -191,99 +156,63 @@ return; } - CommandLine.WriteAction("Pushing " + Name + " .."); - RunShellHg("push"); + TraceSource.TraceEvent(TraceEventType.Information, "Pushing {0}", Name); + RunHg("push"); } - /// Updates the repository by the branch name. - /// + /// Updates the repository by the branch name. public void Update(string branchName) { - CommandLine.WriteAction("Updating branch to " + branchName); - RunShellHg("update " + branchName); + TraceSource.TraceEvent(TraceEventType.Information, "[{0}] Updating branch to {1}", Name, branchName); + RunHg("update " + branchName); } - /// - /// Pulls and updates this clone. - /// - public void PullUpdate() - { - RunShellHg("hg pull"); - RunShellHg("hg update"); - } - - /// - /// Outputs the diff to the default output stream. - /// - public void ShowDiff() - { - RunShellHg("diff"); - } - - /// - /// Creates the combined path of the specified directories. - /// + /// Creates the combined path of the specified directories. public string Combine(params string[] dirs) { return dirs.Aggregate(WorkingDirectory, Path.Combine); } - /// - /// Creates a change list by listing all changes made since the last release. - /// + /// Creates a change list by listing all changes made since the last release. public IEnumerable CreateChangelist() { Regex tagRegex = new Regex("Added tag [0-9A-Za-z.-]+ for changeset [^b]+", RegexOptions.Compiled); string branch = RunListeningHg("branch").Single(); - return RunListeningHg("log --template \"{{rev}}: {{desc}}\\r\\n\" -b {0}", branch) + return RunListeningHg(string.Format("log --template \"{{rev}}: {{desc}}\\r\\n\" -b {0}", branch)) .TakeWhile(line => !tagRegex.IsMatch(line)); } - private void CloneFrom(Uri uri) + /// Runs a HG command. In addition it prints errors and messages to trace. + private void RunHg(string command) { - CommandLine.WriteAction("Fetching " + uri + " .."); - RunHg("clone {0} {1}", uri.ToString(), WorkingDirectory); + RunHg(command, + error => + { + if (!string.IsNullOrEmpty(error)) + { + TraceSource.TraceEvent(TraceEventType.Error, "[{0}] {1}", Name, error); + } + }, + msg => + { + if (!string.IsNullOrEmpty(msg)) + { + TraceSource.TraceEvent(TraceEventType.Information, "[{0}] hg {1}", Name, msg); + } + }); } - private void RunShellHg(string command, params string[] args) - { - RunHg(command, null, null, args); - } - - private void RunHg(string command, params string[] args) - { - RunHg( - command, error => - { - if (!string.IsNullOrEmpty(error)) - { - CommandLine.WriteError(error); - } - }, msg => - { - if (!string.IsNullOrEmpty(msg)) - { - CommandLine.WriteResult("hg", msg); - } - }, args); - } - - private string[] RunListeningHg(string command, params string[] args) - { - var msgs = new List(); - RunHg(command, msgs.Add, msgs.Add, args); - return msgs.ToArray(); - } - - private void RunHg(string command, Action errors, Action msgs, params string[] args) + /// + /// Run a HG command which the specific callback for errors or messages returned from the command. + /// + private void RunHg(string command, Action errorCallback = null, Action messageCallback = null) { var process = new Process(); - string commandLine = string.Format(command, args); - process.StartInfo = new ProcessStartInfo("hg", commandLine); + process.StartInfo = new ProcessStartInfo("hg", command); process.StartInfo.WorkingDirectory = WorkingDirectory; - if (errors != null || msgs != null) + if (errorCallback != null || messageCallback != null) { process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardOutput = true; @@ -292,31 +221,31 @@ } process.Start(); - - if (errors != null) + if (errorCallback != null) { process.ErrorDataReceived += (sender, msg) => - { - if (msg.Data != null) - { - errors(msg.Data); - } - }; + { + if (msg.Data != null) + { + errorCallback(msg.Data); + } + }; process.BeginErrorReadLine(); } - if (msgs != null) + if (messageCallback != null) { process.OutputDataReceived += (sender, msg) => - { - if (msg.Data != null) - { - msgs(msg.Data); - } - }; + { + if (msg.Data != null) + { + messageCallback(msg.Data); + } + }; process.BeginOutputReadLine(); } process.WaitForExit(); + if (process.ExitCode != 0) { string cmdLine = process.StartInfo.FileName + " " + process.StartInfo.Arguments; @@ -324,27 +253,17 @@ } } - /// - /// Clones a new Mercurial repository. - /// - public static Hg Clone(string repository) + /// Runs a HG command and returns all its errors and messages output. + private string[] RunListeningHg(string command) { - return new Hg(new Uri(repository)); - } - - /// - /// Reuses the existing local repository, or creates a new clone of it does not exist. - /// - /// The local Mercurial repository. - /// The remote URL. - public static Hg Get(string localDir, string repository) - { - return new Hg(new Uri(repository), localDir); + var msgs = new List(); + RunHg(command, msgs.Add, msgs.Add); + return msgs.ToArray(); } public void Dispose() { - CommandLine.WriteAction("Cleaning up " + Name + " .."); + TraceSource.TraceEvent(TraceEventType.Information, "[{0}] Cleaning up", Name); Directory.Delete(WorkingDirectory, true); } }