From 9a945cc121279724209cc13286a0d16a63458c4e Mon Sep 17 00:00:00 2001 From: Tim Uy Date: Fri, 22 Jul 2016 00:24:23 -0700 Subject: [PATCH 1/5] add a test to ensure cache key is same even if normalized again; modify cache factory to traverse refs directory instead of just looking at the timestamp (which changes if renormalized) --- src/GitVersionCore.Tests/ExecuteCoreTests.cs | 20 ++++ .../GitVersionCacheKeyFactory.cs | 105 +++++++++++++++++- 2 files changed, 122 insertions(+), 3 deletions(-) diff --git a/src/GitVersionCore.Tests/ExecuteCoreTests.cs b/src/GitVersionCore.Tests/ExecuteCoreTests.cs index 48b6b4647b..9e60778ed3 100644 --- a/src/GitVersionCore.Tests/ExecuteCoreTests.cs +++ b/src/GitVersionCore.Tests/ExecuteCoreTests.cs @@ -18,6 +18,26 @@ public void SetUp() fileSystem = new FileSystem(); } + [Test] + public void CacheKeySameAfterReNormalizing() + { + var versionAndBranchFinder = new ExecuteCore(fileSystem); + + RepositoryScope(versionAndBranchFinder, (fixture, vv) => + { + var targetUrl = "https://github.com/GitTools/GitVersion.git"; + var targetBranch = "refs/head/master"; + var gitPreparer = new GitPreparer(targetUrl, null, new Authentication(), false, fixture.RepositoryPath); + var cacheKey1 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); + gitPreparer.Initialise(true, targetBranch); + var cacheKey2 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); + gitPreparer.Initialise(true, targetBranch); + var cacheKey3 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); + + cacheKey3.Value.ShouldBe(cacheKey2.Value); + }); + } + [Test] public void CacheFileExistsOnDisk() { diff --git a/src/GitVersionCore/GitVersionCacheKeyFactory.cs b/src/GitVersionCore/GitVersionCacheKeyFactory.cs index 5ab9de84a6..c2b00d1949 100644 --- a/src/GitVersionCore/GitVersionCacheKeyFactory.cs +++ b/src/GitVersionCore/GitVersionCacheKeyFactory.cs @@ -2,6 +2,7 @@ { using GitVersion.Helpers; using System; + using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; @@ -23,10 +24,108 @@ private static string GetGitSystemHash(GitPreparer gitPreparer, IFileSystem file { var dotGitDirectory = gitPreparer.GetDotGitDirectory(); - // Maybe using timestamp in .git/refs directory is enough? - var lastGitRefsChangedTicks = fileSystem.GetLastDirectoryWrite(Path.Combine(dotGitDirectory, "refs")); + // traverse the directory and get a list of files, use that for GetHash + var traverse = TraverseTree(Path.Combine(dotGitDirectory, "refs")); - return GetHash(dotGitDirectory, lastGitRefsChangedTicks.ToString()); + return GetHash(traverse.ToArray()); + } + + // lifted from https://msdn.microsoft.com/en-us/library/bb513869.aspx + public static List TraverseTree(string root) + { + var result = new List(); + result.Add(root); + // Data structure to hold names of subfolders to be + // examined for files. + Stack dirs = new Stack(20); + + if (!System.IO.Directory.Exists(root)) + { + throw new ArgumentException(); + } + + dirs.Push(root); + + while (dirs.Count > 0) + { + string currentDir = dirs.Pop(); + + var di = new DirectoryInfo(currentDir); + result.Add(di.Name); + + string[] subDirs; + try + { + subDirs = System.IO.Directory.GetDirectories(currentDir); + } + // An UnauthorizedAccessException exception will be thrown if we do not have + // discovery permission on a folder or file. It may or may not be acceptable + // to ignore the exception and continue enumerating the remaining files and + // folders. It is also possible (but unlikely) that a DirectoryNotFound exception + // will be raised. This will happen if currentDir has been deleted by + // another application or thread after our call to Directory.Exists. The + // choice of which exceptions to catch depends entirely on the specific task + // you are intending to perform and also on how much you know with certainty + // about the systems on which this code will run. + catch (UnauthorizedAccessException e) + { + Logger.WriteError(e.Message); + continue; + } + catch (System.IO.DirectoryNotFoundException e) + { + Logger.WriteError(e.Message); + continue; + } + + string[] files = null; + try + { + files = System.IO.Directory.GetFiles(currentDir); + } + + catch (UnauthorizedAccessException e) + { + Logger.WriteError(e.Message); + continue; + } + + catch (System.IO.DirectoryNotFoundException e) + { + Logger.WriteError(e.Message); + continue; + } + // Perform the required action on each file here. + // Modify this block to perform your required task. + foreach (string file in files) + { + try + { + // Perform whatever action is required in your scenario. + System.IO.FileInfo fi = new System.IO.FileInfo(file); + result.Add(fi.Name); + Logger.WriteInfo(string.Format("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime)); + } + catch (System.IO.FileNotFoundException e) + { + // If file was deleted by a separate application + // or thread since the call to TraverseTree() + // then just continue. + Logger.WriteError(e.Message); + continue; + } + } + + // Push the subdirectories onto the stack for traversal. + // This could also be done before handing the files. + // push in reverse order + for (int i = subDirs.Length - 1; i >= 0; i--) + { + dirs.Push(subDirs[i]); + } + } + + return result; } private static string GetRepositorySnapshotHash(GitPreparer gitPreparer) From 346486583797f7edf89d690ea9136b3c0123c848 Mon Sep 17 00:00:00 2001 From: Tim Uy Date: Fri, 22 Jul 2016 00:57:00 -0700 Subject: [PATCH 2/5] read all the files in .git/refs --- src/GitVersionCore/GitVersionCacheKeyFactory.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/GitVersionCore/GitVersionCacheKeyFactory.cs b/src/GitVersionCore/GitVersionCacheKeyFactory.cs index c2b00d1949..c83b7baaa6 100644 --- a/src/GitVersionCore/GitVersionCacheKeyFactory.cs +++ b/src/GitVersionCore/GitVersionCacheKeyFactory.cs @@ -104,7 +104,11 @@ public static List TraverseTree(string root) // Perform whatever action is required in your scenario. System.IO.FileInfo fi = new System.IO.FileInfo(file); result.Add(fi.Name); - Logger.WriteInfo(string.Format("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime)); + + var reader = fi.OpenText(); + result.Add(reader.ReadToEnd()); + + //Logger.WriteInfo(string.Format("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime)); } catch (System.IO.FileNotFoundException e) { From af3a3f23a37c4c09bed3f80e5d00663071223a67 Mon Sep 17 00:00:00 2001 From: Tim Uy Date: Fri, 22 Jul 2016 07:50:05 -0700 Subject: [PATCH 3/5] suggestions from DanielRose + make sure to close file after reading using ReadAllText --- src/GitVersionCore/GitVersionCacheKeyFactory.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/GitVersionCore/GitVersionCacheKeyFactory.cs b/src/GitVersionCore/GitVersionCacheKeyFactory.cs index c83b7baaa6..5ca64a6298 100644 --- a/src/GitVersionCore/GitVersionCacheKeyFactory.cs +++ b/src/GitVersionCore/GitVersionCacheKeyFactory.cs @@ -104,17 +104,11 @@ public static List TraverseTree(string root) // Perform whatever action is required in your scenario. System.IO.FileInfo fi = new System.IO.FileInfo(file); result.Add(fi.Name); - - var reader = fi.OpenText(); - result.Add(reader.ReadToEnd()); - + result.Add(File.ReadAllText(file)); //Logger.WriteInfo(string.Format("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime)); } - catch (System.IO.FileNotFoundException e) + catch (IOException e) { - // If file was deleted by a separate application - // or thread since the call to TraverseTree() - // then just continue. Logger.WriteError(e.Message); continue; } From 754f93a3d9953498c98d8f61531b625f5cc5f938 Mon Sep 17 00:00:00 2001 From: Tim Uy Date: Sat, 23 Jul 2016 00:30:52 -0700 Subject: [PATCH 4/5] simplifications and code cleanup from pascal --- src/GitVersionCore.Tests/ExecuteCoreTests.cs | 6 ++--- .../GitVersionCacheKeyFactory.cs | 25 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/GitVersionCore.Tests/ExecuteCoreTests.cs b/src/GitVersionCore.Tests/ExecuteCoreTests.cs index 9e60778ed3..cf367edff5 100644 --- a/src/GitVersionCore.Tests/ExecuteCoreTests.cs +++ b/src/GitVersionCore.Tests/ExecuteCoreTests.cs @@ -28,13 +28,13 @@ public void CacheKeySameAfterReNormalizing() var targetUrl = "https://github.com/GitTools/GitVersion.git"; var targetBranch = "refs/head/master"; var gitPreparer = new GitPreparer(targetUrl, null, new Authentication(), false, fixture.RepositoryPath); + //var cacheKey0 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); + gitPreparer.Initialise(true, targetBranch); var cacheKey1 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); gitPreparer.Initialise(true, targetBranch); var cacheKey2 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); - gitPreparer.Initialise(true, targetBranch); - var cacheKey3 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); - cacheKey3.Value.ShouldBe(cacheKey2.Value); + cacheKey2.Value.ShouldBe(cacheKey1.Value); }); } diff --git a/src/GitVersionCore/GitVersionCacheKeyFactory.cs b/src/GitVersionCore/GitVersionCacheKeyFactory.cs index 5ca64a6298..03b7d76cb5 100644 --- a/src/GitVersionCore/GitVersionCacheKeyFactory.cs +++ b/src/GitVersionCore/GitVersionCacheKeyFactory.cs @@ -6,6 +6,7 @@ using System.IO; using System.Security.Cryptography; using System.Text; + using System.Linq; public class GitVersionCacheKeyFactory { @@ -33,20 +34,20 @@ private static string GetGitSystemHash(GitPreparer gitPreparer, IFileSystem file // lifted from https://msdn.microsoft.com/en-us/library/bb513869.aspx public static List TraverseTree(string root) { - var result = new List(); - result.Add(root); + var result = new List { root }; + // Data structure to hold names of subfolders to be // examined for files. - Stack dirs = new Stack(20); + var dirs = new Stack(20); - if (!System.IO.Directory.Exists(root)) + if (!Directory.Exists(root)) { throw new ArgumentException(); } dirs.Push(root); - while (dirs.Count > 0) + while (dirs.Any()) { string currentDir = dirs.Pop(); @@ -56,7 +57,7 @@ public static List TraverseTree(string root) string[] subDirs; try { - subDirs = System.IO.Directory.GetDirectories(currentDir); + subDirs = Directory.GetDirectories(currentDir); } // An UnauthorizedAccessException exception will be thrown if we do not have // discovery permission on a folder or file. It may or may not be acceptable @@ -72,7 +73,7 @@ public static List TraverseTree(string root) Logger.WriteError(e.Message); continue; } - catch (System.IO.DirectoryNotFoundException e) + catch (DirectoryNotFoundException e) { Logger.WriteError(e.Message); continue; @@ -81,7 +82,7 @@ public static List TraverseTree(string root) string[] files = null; try { - files = System.IO.Directory.GetFiles(currentDir); + files = Directory.GetFiles(currentDir); } catch (UnauthorizedAccessException e) @@ -90,19 +91,17 @@ public static List TraverseTree(string root) continue; } - catch (System.IO.DirectoryNotFoundException e) + catch (DirectoryNotFoundException e) { Logger.WriteError(e.Message); continue; } - // Perform the required action on each file here. - // Modify this block to perform your required task. + foreach (string file in files) { try { - // Perform whatever action is required in your scenario. - System.IO.FileInfo fi = new System.IO.FileInfo(file); + var fi = new FileInfo(file); result.Add(fi.Name); result.Add(File.ReadAllText(file)); //Logger.WriteInfo(string.Format("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime)); From 72ad9abc90c412319a885dec399601fce3ce4fca Mon Sep 17 00:00:00 2001 From: Tim Uy Date: Mon, 25 Jul 2016 09:01:59 -0700 Subject: [PATCH 5/5] clear comments, better naming, strip path from content calc --- src/GitVersionCore.Tests/ExecuteCoreTests.cs | 1 - src/GitVersionCore/GitVersionCacheKeyFactory.cs | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/GitVersionCore.Tests/ExecuteCoreTests.cs b/src/GitVersionCore.Tests/ExecuteCoreTests.cs index cf367edff5..57f8c3bddb 100644 --- a/src/GitVersionCore.Tests/ExecuteCoreTests.cs +++ b/src/GitVersionCore.Tests/ExecuteCoreTests.cs @@ -28,7 +28,6 @@ public void CacheKeySameAfterReNormalizing() var targetUrl = "https://github.com/GitTools/GitVersion.git"; var targetBranch = "refs/head/master"; var gitPreparer = new GitPreparer(targetUrl, null, new Authentication(), false, fixture.RepositoryPath); - //var cacheKey0 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); gitPreparer.Initialise(true, targetBranch); var cacheKey1 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); gitPreparer.Initialise(true, targetBranch); diff --git a/src/GitVersionCore/GitVersionCacheKeyFactory.cs b/src/GitVersionCore/GitVersionCacheKeyFactory.cs index 03b7d76cb5..5268d17e38 100644 --- a/src/GitVersionCore/GitVersionCacheKeyFactory.cs +++ b/src/GitVersionCore/GitVersionCacheKeyFactory.cs @@ -26,19 +26,19 @@ private static string GetGitSystemHash(GitPreparer gitPreparer, IFileSystem file var dotGitDirectory = gitPreparer.GetDotGitDirectory(); // traverse the directory and get a list of files, use that for GetHash - var traverse = TraverseTree(Path.Combine(dotGitDirectory, "refs")); + var contents = calculateDirectoryContents(Path.Combine(dotGitDirectory, "refs")); - return GetHash(traverse.ToArray()); + return GetHash(contents.ToArray()); } - // lifted from https://msdn.microsoft.com/en-us/library/bb513869.aspx - public static List TraverseTree(string root) + // based on https://msdn.microsoft.com/en-us/library/bb513869.aspx + private static List calculateDirectoryContents(string root) { - var result = new List { root }; + var result = new List(); // Data structure to hold names of subfolders to be // examined for files. - var dirs = new Stack(20); + var dirs = new Stack(); if (!Directory.Exists(root)) { @@ -104,7 +104,6 @@ public static List TraverseTree(string root) var fi = new FileInfo(file); result.Add(fi.Name); result.Add(File.ReadAllText(file)); - //Logger.WriteInfo(string.Format("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime)); } catch (IOException e) {