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 |
{ |
- /// <summary> |
- /// Mercurial interfacing class |
- /// </summary> |
/// <summary>Mercurial repository interface class.</summary> |
public sealed class Hg : IDisposable |
{ |
- /// <summary> |
- /// Name of the repository. |
- /// </summary> |
static readonly TraceSource TraceSource = new TraceSource("Google.Apis"); |
/// <summary>Gets the name of the repository.summary> |
public string Name { get; private set; } |
- /// <summary> |
- /// The URI of the repositoty |
- /// </summary> |
/// <summary>Gets the URI of the repository</summary> |
public Uri RepositoryUri { get; private set; } |
- /// <summary> |
- /// The local working directory. |
- /// </summary> |
/// <summary>Gets the local working directory.</summary> |
public string WorkingDirectory { get; private set; } |
- /// <summary> |
- /// True if this working copy has pending changes. |
- /// </summary> |
/// <summary>Gets indication if repository has pending changes.</summary> |
public bool HasUncommitedChanges |
{ |
get |
@@ -58,9 51,7 @@ |
} |
} |
- /// <summary> |
- /// True if there are unpulled, incoming changes. |
- /// </summary> |
/// <summary>Gets indication if there are incoming changes.</summary> |
public bool HasIncomingChanges |
{ |
get |
@@ -77,16 68,14 @@ |
} |
} |
- /// <summary> |
- /// True if this working copy has unpushed changes. |
- /// </summary> |
/// <summary>Gets indication if the working copy has un-pushed changes.</summary> |
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) |
/// <summary> |
/// Constructs a new repository. It creates a new repository if the folder doesn't exists, otherwise it gets |
/// the current status of the repository. |
/// </summary> |
/// <param name="repositoryUri">The URI of this repository</param> |
/// <param name="localDir">The local directory which contains the repository files</param> |
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"); |
} |
} |
- /// <summary> |
- /// Commits the pending changes. |
- /// </summary> |
/// <summary>Commits the pending changes.</summary> |
/// <param name="message">Description of the changes/the commit.</param> |
/// <returns>Whether a commit was made/possible.</returns> |
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; |
} |
- /// <summary> |
- /// Adds a tag to the last revision. |
- /// </summary> |
/// <summary>Adds a tag to the last revision.</summary> |
/// <param name="tagName">The tag to add.</param> |
/// <param name="force"> |
- /// 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. |
/// </param> |
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)); |
} |
- /// <summary> |
- /// Adds all unversioned files to the current commit. |
- /// </summary> |
- public void AddUnversionedFiles() |
/// <summary>Adds all unversioned files and remove all versioned files.</summary> |
public void AddRemoveFiles() |
{ |
- RunHg("add"); |
RunHg("addremove"); |
} |
- /// <summary> |
- /// Marks all versioned files which have been deleted as removed. |
- /// </summary> |
- 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); |
- } |
- } |
- |
- /// <summary> |
- /// Pushes all commited changes to the server. |
- /// </summary> |
/// <summary>Pushes all committed changes to the server.</summary> |
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"); |
} |
- /// <summary> Updates the repository by the branch name. </summary> |
- /// <param name="branchName"></param> |
/// <summary>Updates the repository by the branch name.</summary> |
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); |
} |
- /// <summary> |
- /// Pulls and updates this clone. |
- /// </summary> |
- public void PullUpdate() |
- { |
- RunShellHg("hg pull"); |
- RunShellHg("hg update"); |
- } |
- |
- /// <summary> |
- /// Outputs the diff to the default output stream. |
- /// </summary> |
- public void ShowDiff() |
- { |
- RunShellHg("diff"); |
- } |
- |
- /// <summary> |
- /// Creates the combined path of the specified directories. |
- /// </summary> |
/// <summary>Creates the combined path of the specified directories.</summary> |
public string Combine(params string[] dirs) |
{ |
return dirs.Aggregate(WorkingDirectory, Path.Combine); |
} |
- /// <summary> |
- /// Creates a change list by listing all changes made since the last release. |
- /// </summary> |
/// <summary>Creates a change list by listing all changes made since the last release.</summary> |
public IEnumerable<string> 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) |
/// <summary>Runs a HG command. In addition it prints errors and messages to trace.</summary> |
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<string>(); |
- RunHg(command, msgs.Add, msgs.Add, args); |
- return msgs.ToArray(); |
- } |
- |
- private void RunHg(string command, Action<string> errors, Action<string> msgs, params string[] args) |
/// <summary> |
/// Run a HG command which the specific callback for errors or messages returned from the command. |
/// </summary> |
private void RunHg(string command, Action<string> errorCallback = null, Action<string> 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 @@ |
} |
} |
- /// <summary> |
- /// Clones a new Mercurial repository. |
- /// </summary> |
- public static Hg Clone(string repository) |
/// <summary>Runs a HG command and returns all its errors and messages output.</summary> |
private string[] RunListeningHg(string command) |
{ |
- return new Hg(new Uri(repository)); |
- } |
- |
- /// <summary> |
- /// Reuses the existing local repository, or creates a new clone of it does not exist. |
- /// </summary> |
- /// <param name="localDir">The local Mercurial repository.</param> |
- /// <param name="repository">The remote URL.</param> |
- public static Hg Get(string localDir, string repository) |
- { |
- return new Hg(new Uri(repository), localDir); |
var msgs = new List<string>(); |
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); |
} |
} |