private VaultTxDetailHistoryItem [] GetChanges( VaultClientHelper client, VaultTxHistoryItem changeSet ) { string changeSetComment = null; VaultTxDetailHistoryItem [] changes = { }; client.Client.Connection.GetTxDetail( client.Client.ActiveRepositoryID, changeSet.TxID, ref changeSetComment, ref changes ); FillInMissingComments( changes, changeSetComment ); return changes; }
private VaultTxDetailHistoryItem [] GetChanges(VaultClientHelper client, VaultTxHistoryItem changeSet) { string changeSetComment = null; VaultTxDetailHistoryItem [] changes = { }; client.Client.Connection.GetTxDetail(client.Client.ActiveRepositoryID, changeSet.TxID, ref changeSetComment, ref changes); FillInMissingComments(changes, changeSetComment); return(changes); }
private bool HandleInitialCheckouts(VaultTxHistoryItem startingTxHistoryItem, string vaultRepoPath) { if (startingTxHistoryItem == null && !_beginDate.HasValue) { return(false); } var needsInitialCommit = false; foreach (var vaultSubDirectory in _vaultSubdirectories) { var fsPath = Path.Combine(WorkingFolder, vaultSubDirectory); if (string.IsNullOrEmpty(vaultSubDirectory)) { if (Directory.GetDirectories(fsPath).Any(x => !x.Contains(".git"))) { continue; } } else if (Directory.Exists(fsPath)) { continue; } var subdirTxItems = _vault.VaultGetTxHistoryItems(vaultRepoPath, vaultSubDirectory); // It's possible there was no commit to vault since _beginDate. To make behaviour consistent with all history merge style let's get the latest versions in case folder is empty VaultTxHistoryItem folderTxItem = null; if (startingTxHistoryItem != null) { folderTxItem = subdirTxItems.FirstOrDefault(x => x.TxID == startingTxHistoryItem.TxID); } if (folderTxItem == null && _beginDate.HasValue) { folderTxItem = subdirTxItems.LastOrDefault(x => x.TxDate.GetDateTime() < _beginDate.Value); } if (folderTxItem != null) { _vault.VaultGetVersion(vaultRepoPath, vaultSubDirectory, folderTxItem.Version, true); needsInitialCommit = true; } } return(needsInitialCommit); }
private void GetAndCommitTransaction(string vaultRepoPath, VaultTxHistoryItem txHistoryItem, TxInfo txInfo, string gitBranch, Stopwatch perTransactionWatch) { var files = string.Join(",", txInfo.items.Select(x => string.IsNullOrEmpty(x.ItemPath1) ? x.Name : x.ItemPath1)); Log.Debug($"Processing transaction ID {txHistoryItem.TxID}: commit time: {txHistoryItem.TxDate.GetDateTime():u}, comment: {txHistoryItem.Comment}, author: {txHistoryItem.UserLogin}, files/dirs: {files}"); var itemsFailedToGet = new HashSet <string>(); // It has been noticed that renames tend to be listed at the end of txnInfo.items. Make sure this event precedes content updates foreach (var txDetailItem in txInfo.items.OrderBy(x => x.RequestType != VaultRequestType.Rename && x.RequestType != VaultRequestType.Move)) { if (!TryFindMatchingSubdir(vaultRepoPath, txDetailItem.ItemPath1, out var vaultSubdirectory) && !TryFindMatchingSubdir(vaultRepoPath, txDetailItem.ItemPath2, out vaultSubdirectory)) { continue; } if (ForceFullFolderGet) { continue; } var itemPath = RemoveRepoFromItemPath(vaultRepoPath, string.IsNullOrEmpty(txDetailItem.ItemPath1) ? txDetailItem.Name : txDetailItem.ItemPath1); var versionToGet = txDetailItem.Version; switch (txDetailItem.RequestType) { // Do deletions, renames and moves ourselves case VaultRequestType.Delete: { var filesystemPath = txDetailItem.ItemPath1.Replace(vaultRepoPath, WorkingFolder); if (File.Exists(filesystemPath)) { File.Delete(filesystemPath); } else if (Directory.Exists(filesystemPath)) { Directory.Delete(filesystemPath, true); } continue; } case VaultRequestType.Share: case VaultRequestType.CheckOut: case VaultRequestType.LabelItem: case VaultRequestType.AddFolder: // Nothing in a CopyBranch to do. Its just a place marker case VaultRequestType.CopyBranch: // Git doesn't add empty folders continue; case VaultRequestType.Move: case VaultRequestType.Rename: { Log.Debug($"Handling rename/move from {txDetailItem.ItemPath1} to {txDetailItem.ItemPath2}"); var item1NoRepoPath = RemoveRepoFromItemPath(vaultRepoPath, txDetailItem.ItemPath1); var item1FsPath = Path.Combine(WorkingFolder, item1NoRepoPath); var item2NoRepoPath = txDetailItem.RequestType == VaultRequestType.Move ? RemoveRepoFromItemPath(vaultRepoPath, txDetailItem.ItemPath2) : // Move item1NoRepoPath.Remove(item1NoRepoPath.Length - Path.GetFileName(txDetailItem.ItemPath1).Length) + txDetailItem.ItemPath2; // Rename var item2FsPath = Path.Combine(WorkingFolder, item2NoRepoPath); DeleteFileOrFolder(item2FsPath); if (!TryFindMatchingSubdir(vaultRepoPath, item2NoRepoPath, out _)) { DeleteFileOrFolder(item1FsPath); continue; } if (Directory.Exists(item1FsPath)) { var item2FsPathNoSlashEnding = item2FsPath.EndsWith("/") || item2FsPath.EndsWith("\\") ? item2FsPath.Substring(item2FsPath.Length - 1) : item2FsPath; Directory.CreateDirectory(Path.GetDirectoryName(item2FsPathNoSlashEnding)); Directory.Move(item1FsPath, item2FsPath); } else if (File.Exists(item1FsPath)) { Directory.CreateDirectory(Path.GetDirectoryName(item2FsPath)); File.Move(item1FsPath, item2FsPath); } else { versionToGet = txDetailItem.OtherVersion; itemPath = item2NoRepoPath; break; } continue; } } // Apply the changes from vault of the correct version for this file try { _vault.VaultGetVersion(vaultRepoPath, itemPath, versionToGet, false); } catch { itemsFailedToGet.Add(itemPath); continue; } var fsPath = Path.Combine(WorkingFolder, itemPath); if (!File.Exists(fsPath)) { continue; } // Remove Source Code Control switch (Path.GetExtension(fsPath).ToLower()) { case ".sln": RemoveSccFromSln(fsPath); break; case ".csproj": RemoveSccFromCsProj(fsPath); break; case ".vdproj": RemoveSccFromVdProj(fsPath); break; } } GetParentsOfFailedItems(vaultRepoPath, itemsFailedToGet, txHistoryItem.TxID); if (GitCommit(vaultRepoPath, txHistoryItem.TxID, gitBranch, txHistoryItem.UserLogin, txHistoryItem.Comment, txHistoryItem.TxDate.GetDateTime())) { Log.Information($"Committing transaction {txHistoryItem.TxID} took {perTransactionWatch.Elapsed}. Author: {txHistoryItem.UserLogin}, Comment: {txHistoryItem.Comment}, commit time: {txHistoryItem.TxDate.GetDateTime():u}"); } perTransactionWatch.Restart(); }
/// <summary> /// Pulls versions /// </summary> /// <param name="git2VaultRepoPath">Key=git, Value=vault</param> /// <returns>True if something has been committed. False otherwise</returns> public void Pull(IEnumerable <KeyValuePair <string, string> > git2VaultRepoPath) { //get git current branch name _git.GitCurrentBranch(out _originalGitBranch); Log.Information($"Starting git branch is {_originalGitBranch}"); //reorder target branches to start from current branch, so don't need to do checkout for first branch var targetList = git2VaultRepoPath.OrderByDescending(p => p.Key.Equals(_originalGitBranch, StringComparison.CurrentCultureIgnoreCase)); try { _vault.VaultLogin(); foreach (var pair in targetList) { var perBranchWatch = Stopwatch.StartNew(); var gitBranch = pair.Key; var vaultRepoPath = pair.Value; Log.Information($"\nProcessing git branch {gitBranch}"); Init(vaultRepoPath, gitBranch); if (!_vault.IsSetRootVaultWorkingFolder()) { Environment.Exit(1); } var txHistoryItems = new SortedSet <VaultTxHistoryItem>(new VaultTxHistoryItemComparer()); //get current Git version var startingGitVaultVersion = _git.GitVaultVersion(gitBranch, VaultTagStem, BuildVaultTag(vaultRepoPath)); //get vault versions foreach (var subdirTxItems in _vaultSubdirectories.Select(vaultSubDirectory => _vault.VaultGetTxHistoryItems(vaultRepoPath, vaultSubDirectory))) { var maybeDateFilteredTxItems = _beginDate.HasValue ? subdirTxItems.Where(txItem => txItem.TxDate.GetDateTime() >= _beginDate.Value) : subdirTxItems; txHistoryItems.UnionWith(maybeDateFilteredTxItems); } // Filter all committed vault versions VaultTxHistoryItem startingTxHistoryItem = null; if (startingGitVaultVersion.HasValue) { var enumerable = txHistoryItems.SkipWhile(x => x.TxID != startingGitVaultVersion.Value); startingTxHistoryItem = enumerable.FirstOrDefault(); var passCurrentGitVersion = enumerable.Skip(1); txHistoryItems = new SortedSet <VaultTxHistoryItem>(passCurrentGitVersion, new VaultTxHistoryItemComparer()); } var needsInitialCommit = HandleInitialCheckouts(startingTxHistoryItem, vaultRepoPath); if (needsInitialCommit) { GitCommit(vaultRepoPath, startingGitVaultVersion ?? 0, gitBranch, Mergetool, "Initialising some folders", DateTime.UtcNow); } Log.Information($"init took {perBranchWatch.Elapsed}"); var counter = 0; var sampledItems = new List <Tuple <VaultTxHistoryItem, TxInfo> >(); var perTransactionWatch = Stopwatch.StartNew(); foreach (var txHistoryItem in txHistoryItems) { TxInfo txInfo; try { txInfo = _vault.GetTxInfo(txHistoryItem.TxID); } catch (Exception e) { Log.Warning($"Failed to get transaction info for {txHistoryItem.TxDate.GetDateTime():u}, txID={txHistoryItem.TxID}, author={txHistoryItem.UserLogin}, comment={txHistoryItem.Comment}\n\n{e}"); continue; } if (_sampleTimeWhenNoFullPathAvailable.HasValue && txInfo.items.All(x => string.IsNullOrEmpty(x.ItemPath1))) { if (sampledItems.Count > 0 && (txHistoryItem.TxDate - sampledItems[0].Item1.TxDate >= _sampleTimeWhenNoFullPathAvailable.Value)) { ++counter; GetAndCommitSampledTransactions(vaultRepoPath, sampledItems, gitBranch, perTransactionWatch); } sampledItems.Add(Tuple.Create(txHistoryItem, txInfo)); } else { ++counter; GetAndCommitTransaction(vaultRepoPath, txHistoryItem, txInfo, gitBranch, perTransactionWatch); } //check if limit is reached if (_maxTxCount.HasValue && counter >= _maxTxCount) { break; } } GetAndCommitSampledTransactions(vaultRepoPath, sampledItems, gitBranch, perTransactionWatch); _vault.UnSetVaultWorkingFolder(vaultRepoPath); _git.GitCheckout(_originalGitBranch); // Return to original Git branch } } finally { var finalizeWatch = Stopwatch.StartNew(); Log.Information("\n"); //complete _vault.VaultLogout(); //finalize git (update server info for dumb clients) _git.GitFinalize(); Log.Information($"finalization took {finalizeWatch.Elapsed}"); } }