diff --git a/KuduSync.NET/FileInfoBaseExtensions.cs b/KuduSync.NET/FileInfoBaseExtensions.cs index 368d82d..fc99331 100644 --- a/KuduSync.NET/FileInfoBaseExtensions.cs +++ b/KuduSync.NET/FileInfoBaseExtensions.cs @@ -19,5 +19,14 @@ public static string ComputeSha1(this FileInfoBase file) return BitConverter.ToString(sha1.ComputeHash(fileStream)); } } + + public static string ComputeSha256(this FileInfoBase file) + { + using (var fileStream = file.OpenRead()) + { + var sha256 = new SHA256Managed(); + return BitConverter.ToString(sha256.ComputeHash(fileStream)); + } + } } } diff --git a/KuduSync.NET/KuduSync.cs b/KuduSync.NET/KuduSync.cs index b960403..11ed8d5 100644 --- a/KuduSync.NET/KuduSync.cs +++ b/KuduSync.NET/KuduSync.cs @@ -65,6 +65,17 @@ public KuduSync(KuduSyncOptions options, Logger logger) { _to = Path.Combine(_to, _targetSubFolder); } + + if (_options.HashOnly) + { + _logger.Log("Hash only mode ON"); + } + + if (_options.Verbose) + { + _logger.Log("Verbose logging ON"); + } + } private bool TryCleanupToBeDeletedDirectory() @@ -121,13 +132,12 @@ public void Run() _nextManifest.SaveManifestFile(); TryCleanupToBeDeletedDirectory(); + + _logger.Log("Kudusync.NET Complete"); } - private void SmartCopy(string sourcePath, - string destinationPath, - string targetSubFolder, - DirectoryInfoBase sourceDirectory, - DirectoryInfoBase destinationDirectory) + //Main method + private void SmartCopy(string sourcePath,string destinationPath,string targetSubFolder,DirectoryInfoBase sourceDirectory,DirectoryInfoBase destinationDirectory) { if (IgnorePath(sourceDirectory)) { @@ -165,6 +175,7 @@ private void SmartCopy(string sourcePath, // Trim the start destinationFilePath string previousPath = FileSystemHelpers.GetRelativePath(destinationPath, destFile.FullName); + if (!sourceFilesLookup.ContainsKey(destFile.Name) && DoesPathExistsInManifest(previousPath, targetSubFolder)) { _logger.Log("Deleting file: '{0}'", previousPath); @@ -184,26 +195,44 @@ private void SmartCopy(string sourcePath, // if the file exists in the destination then only copy it again if it's // last write time is different than the same file in the source (only if it changed) FileInfoBase targetFile; - if (destFilesLookup.TryGetValue(sourceFile.Name, out targetFile) && - sourceFile.LastWriteTimeUtc == targetFile.LastWriteTimeUtc) - { - continue; - } + + var details = FileSystemHelpers.GetRelativePath(sourcePath, sourceFile.FullName) + (_options.CopyMetaData ? " " + ShorthandAttributes(sourceFile) : String.Empty); string path = FileSystemHelpers.GetDestinationPath(sourcePath, destinationPath, sourceFile); - var details = FileSystemHelpers.GetRelativePath(sourcePath, sourceFile.FullName) + (_options.CopyMetaData ? " " + ShorthandAttributes(sourceFile) : String.Empty); + switch (_options.HashOnly) + { + case true: //behaviour added by JWC on 8/11/2016 + if (destFilesLookup.TryGetValue(sourceFile.Name, out targetFile) && sourceFile.ComputeSha256() == targetFile.ComputeSha256()) //if destination contins file, and the hash matched + { + if(_options.Verbose) + _logger.Log("Hash match on {0}, will not copy", details); + //move to next iteration if file the same + continue; + } + break; + case false: + if (destFilesLookup.TryGetValue(sourceFile.Name, out targetFile) && sourceFile.LastWriteTimeUtc == targetFile.LastWriteTimeUtc) //if destination contains file, and the time matches + { + //move to next iteration if file the same + continue; + } + break; + } + + //if file is not the same, the code below executes if (sourceFile.IsWebConfig()) { - // If current file is web.config check the content sha1. - if (!destFilesLookup.TryGetValue(sourceFile.Name, out targetFile) || - !sourceFile.ComputeSha1().Equals(targetFile.ComputeSha1())) - { + // If current file is web.config check the content sha256. + + //if (!destFilesLookup.TryGetValue(sourceFile.Name, out targetFile) && !sourceFile.ComputeSha256().Equals(targetFile.ComputeSha256())) //if destination does not contain file OR the hash matches + //{ // Save the file path to copy later for copying web.config forces an appDomain // restart right away without respecting waitChangeNotification _filesToCopyLast.Add(Tuple.Create(sourceFile, path, details)); - } + //} + continue; } diff --git a/KuduSync.NET/KuduSyncOptions.cs b/KuduSync.NET/KuduSyncOptions.cs index 7b873ae..b7337d2 100644 --- a/KuduSync.NET/KuduSyncOptions.cs +++ b/KuduSync.NET/KuduSyncOptions.cs @@ -39,8 +39,8 @@ public class KuduSyncOptions : CommandLineOptionsBase [Option("q", "quiet", Required = false, HelpText = "No logging")] public bool Quiet { get; set; } - [Option("v", "verbose", Required = false, HelpText = "Verbose logging with maximum number of output lines")] - public int? Verbose { get; set; } + [Option("v", "verbose", DefaultValue = false, Required = false, HelpText = "Verbose logging with maximum number of output lines")] + public bool Verbose { get; set; } [Option("w", "whatIf", Required = false, HelpText = "Only log without actual copy/remove of files")] public bool WhatIf { get; set; } @@ -48,6 +48,9 @@ public class KuduSyncOptions : CommandLineOptionsBase [Option("", "perf", Required = false, HelpText = "Print out the time it took to complete KuduSync operation")] public bool Perf { get; set; } + [Option("h", "hashOnly", DefaultValue = false, Required = false, HelpText = "Compare files by contents only using SHA256")] + public bool HashOnly { get; set; } + [HelpOption] public string GetUsage() { diff --git a/KuduSync.NET/Logger.cs b/KuduSync.NET/Logger.cs index c19f459..32f144f 100644 --- a/KuduSync.NET/Logger.cs +++ b/KuduSync.NET/Logger.cs @@ -1,5 +1,7 @@ using System; +using System.Diagnostics; using System.IO; +using System.Runtime.Remoting.Messaging; using System.Text; namespace KuduSync.NET @@ -19,15 +21,34 @@ public class Logger : IDisposable /// sets the verbosity, 0 is verbose, less is quiet, more is the number of maximum log lines to write. public Logger(int maxLogLines) { - var stream = Console.OpenStandardOutput(); - _writer = new StreamWriter(stream); + Stream stream = Console.OpenStandardOutput(); + _writer = new KuduSyncLogger(stream); _maxLogLines = maxLogLines; } + + public class KuduSyncLogger : StreamWriter + { + public KuduSyncLogger(Stream stream): base(stream) + { + + + } + + public override void WriteLine(string value) + { + Debug.WriteLine(value); + base.WriteLine(value); + } + } + + + public void Log(string format, params object[] args) { bool logged = false; + if (_maxLogLines == 0 || _logCounter < _maxLogLines) { _writer.WriteLine(format, args); diff --git a/KuduSync.NET/Program.cs b/KuduSync.NET/Program.cs index 2fd5064..c0264fe 100644 --- a/KuduSync.NET/Program.cs +++ b/KuduSync.NET/Program.cs @@ -18,7 +18,7 @@ static int Main(string[] args) ICommandLineParser parser = new CommandLineParser(); if (parser.ParseArguments(args, kuduSyncOptions)) { - using (var logger = GetLogger(kuduSyncOptions)) + using (Logger logger = GetLogger(kuduSyncOptions)) { new KuduSync(kuduSyncOptions, logger).Run(); } @@ -53,13 +53,13 @@ private static Logger GetLogger(KuduSyncOptions kuduSyncOptions) { maxLogLines = -1; } - else if (kuduSyncOptions.Verbose != null) + else if (kuduSyncOptions.Verbose) { - maxLogLines = kuduSyncOptions.Verbose.Value; + maxLogLines = int.MaxValue; } else { - maxLogLines = 0; + maxLogLines = 100; } return new Logger(maxLogLines);