diff --git a/src/GitVersionCore.Tests/ExecuteCoreTests.cs b/src/GitVersionCore.Tests/ExecuteCoreTests.cs index 48b6b4647b..57f8c3bddb 100644 --- a/src/GitVersionCore.Tests/ExecuteCoreTests.cs +++ b/src/GitVersionCore.Tests/ExecuteCoreTests.cs @@ -18,6 +18,25 @@ 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); + gitPreparer.Initialise(true, targetBranch); + var cacheKey1 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); + gitPreparer.Initialise(true, targetBranch); + var cacheKey2 = GitVersionCacheKeyFactory.Create(fileSystem, gitPreparer, null); + + cacheKey2.Value.ShouldBe(cacheKey1.Value); + }); + } + [Test] public void CacheFileExistsOnDisk() { diff --git a/src/GitVersionCore/GitVersionCacheKeyFactory.cs b/src/GitVersionCore/GitVersionCacheKeyFactory.cs index 5ab9de84a6..5268d17e38 100644 --- a/src/GitVersionCore/GitVersionCacheKeyFactory.cs +++ b/src/GitVersionCore/GitVersionCacheKeyFactory.cs @@ -2,9 +2,11 @@ { using GitVersion.Helpers; using System; + using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; + using System.Linq; public class GitVersionCacheKeyFactory { @@ -23,10 +25,103 @@ 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 contents = calculateDirectoryContents(Path.Combine(dotGitDirectory, "refs")); - return GetHash(dotGitDirectory, lastGitRefsChangedTicks.ToString()); + return GetHash(contents.ToArray()); + } + + // based on https://msdn.microsoft.com/en-us/library/bb513869.aspx + private static List calculateDirectoryContents(string root) + { + var result = new List(); + + // Data structure to hold names of subfolders to be + // examined for files. + var dirs = new Stack(); + + if (!Directory.Exists(root)) + { + throw new ArgumentException(); + } + + dirs.Push(root); + + while (dirs.Any()) + { + string currentDir = dirs.Pop(); + + var di = new DirectoryInfo(currentDir); + result.Add(di.Name); + + string[] subDirs; + try + { + 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 + // 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 (DirectoryNotFoundException e) + { + Logger.WriteError(e.Message); + continue; + } + + string[] files = null; + try + { + files = Directory.GetFiles(currentDir); + } + + catch (UnauthorizedAccessException e) + { + Logger.WriteError(e.Message); + continue; + } + + catch (DirectoryNotFoundException e) + { + Logger.WriteError(e.Message); + continue; + } + + foreach (string file in files) + { + try + { + var fi = new FileInfo(file); + result.Add(fi.Name); + result.Add(File.ReadAllText(file)); + } + catch (IOException e) + { + 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)