From fc1365d8fa4cd4b5dfeb22e33c03c3eb00867652 Mon Sep 17 00:00:00 2001 From: Gordon Burgett Date: Tue, 9 Apr 2013 09:01:14 -0500 Subject: [PATCH] TfsHelper can now map multiple paths in a workspace, remotes now map all paths for all subtrees Signed-off-by: Gordon Burgett --- GitTfs.VsCommon/TfsHelper.Common.cs | 28 +++++++++++++-- GitTfs/Commands/Subtree.cs | 52 ++++++++++++++++++++-------- GitTfs/Core/GitRepository.cs | 14 ++++++++ GitTfs/Core/GitTfsRemote.cs | 11 +++++- GitTfs/Core/IGitRepository.cs | 5 +++ GitTfs/Core/TfsInterop/ITfsHelper.cs | 11 ++++++ 6 files changed, 102 insertions(+), 19 deletions(-) diff --git a/GitTfs.VsCommon/TfsHelper.Common.cs b/GitTfs.VsCommon/TfsHelper.Common.cs index fd71e267b..7d48e995d 100644 --- a/GitTfs.VsCommon/TfsHelper.Common.cs +++ b/GitTfs.VsCommon/TfsHelper.Common.cs @@ -195,10 +195,31 @@ private ITfsChangeset BuildTfsChangeset(Changeset changeset, GitTfsRemote remote return tfsChangeset; } + public void WithWorkspace(string localDirectory, IGitTfsRemote remote, IEnumerable> mappings, TfsChangesetInfo versionToFetch, Action action) + { + Trace.WriteLine("Setting up a TFS workspace for multiple remotes"); + var folders = mappings.Select(x => new WorkingFolder(Path.Combine(localDirectory, x.Item1), x.Item2)).ToArray(); + var workspace = GetWorkspace(folders); + try + { + var tfsWorkspace = _container.With("localDirectory").EqualTo(localDirectory) + .With("remote").EqualTo(remote) + .With("contextVersion").EqualTo(versionToFetch) + .With("workspace").EqualTo(_bridge.Wrap(workspace)) + .With("tfsHelper").EqualTo(this) + .GetInstance(); + action(tfsWorkspace); + } + finally + { + workspace.Delete(); + } + } + public void WithWorkspace(string localDirectory, IGitTfsRemote remote, TfsChangesetInfo versionToFetch, Action action) { Trace.WriteLine("Setting up a TFS workspace at " + localDirectory); - var workspace = GetWorkspace(localDirectory, remote.TfsRepositoryPath); + var workspace = GetWorkspace(new WorkingFolder(localDirectory, remote.TfsRepositoryPath)); try { var tfsWorkspace = _container.With("localDirectory").EqualTo(localDirectory) @@ -215,12 +236,13 @@ public void WithWorkspace(string localDirectory, IGitTfsRemote remote, TfsChange } } - private Workspace GetWorkspace(string localDirectory, string repositoryPath) + private Workspace GetWorkspace(params WorkingFolder[] folders) { var workspace = VersionControl.CreateWorkspace(GenerateWorkspaceName()); try { - workspace.CreateMapping(new WorkingFolder(repositoryPath, localDirectory)); + foreach(WorkingFolder folder in folders) + workspace.CreateMapping(folder); } catch (MappingConflictException e) { diff --git a/GitTfs/Commands/Subtree.cs b/GitTfs/Commands/Subtree.cs index 014b3699c..b9ef8fda9 100644 --- a/GitTfs/Commands/Subtree.cs +++ b/GitTfs/Commands/Subtree.cs @@ -90,26 +90,48 @@ public int DoAdd(string tfsUrl, string tfsRepositoryPath) var fetch = Squash ? this._quickFetch : this._fetch; + + //create a remote for the new subtree string remoteId = "subtree/" + Prefix; - IGitTfsRemote remote; - if (_globals.Repository.HasRemote(remoteId)) + IGitTfsRemote remote = _globals.Repository.CreateTfsRemote(new RemoteInfo { - remote = _globals.Repository.ReadTfsRemote(remoteId); - } - else + Id = remoteId, + Url = tfsUrl, + Repository = tfsRepositoryPath, + RemoteOptions = _remoteOptions, + }); + _stdout.WriteLine("-> new remote " + remote.Id); + + var tfsUri = new Uri(tfsUrl); + IGitTfsRemote owner = _globals.Repository.ReadAllTfsRemotes().FirstOrDefault(x => !x.Id.StartsWith("subtree/") && tfsUri.Equals(x.TfsUrl)); + if (owner == null) { - //create a remote for the new subtree - remote = _globals.Repository.CreateTfsRemote(new RemoteInfo + try { - Id = remoteId, - Url = tfsUrl, - Repository = tfsRepositoryPath, - RemoteOptions = _remoteOptions, - }); - _stdout.WriteLine("-> new remote " + remote.Id); - } - + owner = _globals.Repository.CreateTfsRemote(new RemoteInfo + { + Id = "origin", + Url = tfsUrl, + Repository = "", + RemoteOptions = _remoteOptions + }); + } + catch (Exception) + { + //need to clean up our subtree + try + { + _globals.Repository.DeleteTfsRemote(remote); + } + catch + { + + } + throw; + } + } + int result = fetch.Run(remote.Id); if (result == GitTfsExitCodes.OK) diff --git a/GitTfs/Core/GitRepository.cs b/GitTfs/Core/GitRepository.cs index 8a9ff86a5..c4c5506dc 100644 --- a/GitTfs/Core/GitRepository.cs +++ b/GitTfs/Core/GitRepository.cs @@ -475,5 +475,19 @@ public void Reset(string sha, ResetOptions resetOptions) { _repository.Reset(resetOptions, sha); } + + /// + /// Gets all configured "subtree" remotes which point to the same Tfs URL as the given remote. + /// If the given remote is itself a subtree, an empty enumerable is returned. + /// + public IEnumerable GetSubtrees(IGitTfsRemote owner) + { + //a subtree remote cannot have subtrees itself. + if (owner.Id.StartsWith("subtree/")) + return Enumerable.Empty(); + + var uri = new Uri(owner.TfsUrl); + return ReadAllTfsRemotes().Where(x => x.Id.StartsWith("subtree/") && uri.Equals(x.TfsUrl)); + } } } diff --git a/GitTfs/Core/GitTfsRemote.cs b/GitTfs/Core/GitTfsRemote.cs index b7eca3c39..3e811e699 100644 --- a/GitTfs/Core/GitTfsRemote.cs +++ b/GitTfs/Core/GitTfsRemote.cs @@ -546,7 +546,16 @@ private void WithWorkspace(TfsChangesetInfo parentChangeset, Action new Tuple(x.Id.Substring("subtree/".Length), x.TfsRepositoryPath)), parentChangeset, action); + } + else + { + Tfs.WithWorkspace(WorkingDirectory, this, parentChangeset, action); + } } private long Checkin(string head, string parent, ITfsWorkspace workspace, CheckinOptions options) diff --git a/GitTfs/Core/IGitRepository.cs b/GitTfs/Core/IGitRepository.cs index f5b74917c..a4919af98 100644 --- a/GitTfs/Core/IGitRepository.cs +++ b/GitTfs/Core/IGitRepository.cs @@ -38,5 +38,10 @@ public interface IGitRepository : IGitHelpers void CreateNote(string sha, string content, string owner, string emailOwner, DateTime creationDate); void MoveRemote(string oldRemoteName, string newRemoteName); void Reset(string sha, ResetOptions resetOptions); + /// + /// Gets all configured "subtree" remotes which point to the same Tfs URL as the given remote. + /// If the given remote is itself a subtree, an empty enumerable is returned. + /// + IEnumerable GetSubtrees(IGitTfsRemote owner); } } diff --git a/GitTfs/Core/TfsInterop/ITfsHelper.cs b/GitTfs/Core/TfsInterop/ITfsHelper.cs index 8ed4434ad..5464b0893 100644 --- a/GitTfs/Core/TfsInterop/ITfsHelper.cs +++ b/GitTfs/Core/TfsInterop/ITfsHelper.cs @@ -33,5 +33,16 @@ public interface ITfsHelper IEnumerable GetBranches(); void EnsureAuthenticated(); void CreateBranch(string sourcePath, string targetPath, int changesetId, string comment = null); + + /// + /// Creates and maps a workspace for the given remote with the given local -> server directory mappings, at the given Tfs version, + /// and then performs the action. + /// + /// The local base directory containing all the mappings + /// The owning remote + /// The workspace mappings to create. Item1 is the relative path from the localDirectory, and Item2 is the TfsRepositoryPath + /// The TFS version to fetch from the server + /// The action to perform + void WithWorkspace(string localDirectory, IGitTfsRemote remote, IEnumerable> mappings, TfsChangesetInfo versionToFetch, Action action); } }