Commit 38e7286ed407d031e0902155319fb827016f1d51
1 parent
027cf126
v 1.34.0
- CompareDirectories funkció beépítése
Showing
3 changed files
with
181 additions
and
7 deletions
Show diff stats
Vrh.Log4Pro.MaintenanceConsole/ConsoleFunction - CommandLineParser.cs
| @@ -288,12 +288,18 @@ namespace Vrh.Log4Pro.MaintenanceConsole.CommandLineParserNS | @@ -288,12 +288,18 @@ namespace Vrh.Log4Pro.MaintenanceConsole.CommandLineParserNS | ||
| 288 | public static class Functions | 288 | public static class Functions |
| 289 | { | 289 | { |
| 290 | public const string CMD_PACKAGES = "-PACKAGES"; | 290 | public const string CMD_PACKAGES = "-PACKAGES"; |
| 291 | - public static class CreateBackupPackage | 291 | + public const string CMD_DIR1 = "-DIR1"; |
| 292 | + public const string CMD_DIR2 = "-DIR2"; | ||
| 293 | + public static class CreateBackupPackage | ||
| 292 | { | 294 | { |
| 293 | public const string KEY = "CRE"; | 295 | public const string KEY = "CRE"; |
| 294 | } | 296 | } |
| 295 | - } | ||
| 296 | - } | 297 | + public static class CompareDirectories |
| 298 | + { | ||
| 299 | + public const string KEY = "COM"; | ||
| 300 | + } | ||
| 301 | + } | ||
| 302 | + } | ||
| 297 | public static class SQLDataBaseManager | 303 | public static class SQLDataBaseManager |
| 298 | { | 304 | { |
| 299 | public const string KEY = "SQL"; | 305 | public const string KEY = "SQL"; |
Vrh.Log4Pro.MaintenanceConsole/Manager - BackupPackageManager.cs
| @@ -22,6 +22,7 @@ using Vrh.XmlProcessing; | @@ -22,6 +22,7 @@ using Vrh.XmlProcessing; | ||
| 22 | using VRH.Common; | 22 | using VRH.Common; |
| 23 | using System.Xml.Linq; | 23 | using System.Xml.Linq; |
| 24 | using System.Text.RegularExpressions; | 24 | using System.Text.RegularExpressions; |
| 25 | +using System.Security.Cryptography; | ||
| 25 | 26 | ||
| 26 | namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS | 27 | namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS |
| 27 | { | 28 | { |
| @@ -42,7 +43,8 @@ namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS | @@ -42,7 +43,8 @@ namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS | ||
| 42 | 43 | ||
| 43 | var menufunctions = new Menu("Manage Backup Packages", "Select the management function!") | 44 | var menufunctions = new Menu("Manage Backup Packages", "Select the management function!") |
| 44 | .AddMenuItem(new Menu.Item(CLP.Module.BackupPackageManager.Functions.CreateBackupPackage.KEY, "Create backup package", CreateBackupPackage,ep)) | 45 | .AddMenuItem(new Menu.Item(CLP.Module.BackupPackageManager.Functions.CreateBackupPackage.KEY, "Create backup package", CreateBackupPackage,ep)) |
| 45 | - .SetSelectionMode(Menu.SelectionMode.Single) | 46 | + .AddMenuItem(new Menu.Item(CLP.Module.BackupPackageManager.Functions.CompareDirectories.KEY, "Compare directories", CompareDirectories, ep)) |
| 47 | + .SetSelectionMode(Menu.SelectionMode.Single) | ||
| 46 | .SetMenuHeaderDisplayer(BackupPackageListDisplayer); | 48 | .SetMenuHeaderDisplayer(BackupPackageListDisplayer); |
| 47 | menufunctions.ExecuteMenu(functionkey); | 49 | menufunctions.ExecuteMenu(functionkey); |
| 48 | return o2; | 50 | return o2; |
| @@ -50,7 +52,173 @@ namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS | @@ -50,7 +52,173 @@ namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS | ||
| 50 | #endregion Execute | 52 | #endregion Execute |
| 51 | 53 | ||
| 52 | #region First level Executors with UI | 54 | #region First level Executors with UI |
| 53 | - private static object CreateBackupPackage(object parameter, object o) | 55 | + internal static object CompareDirectories(object parameter, object o) |
| 56 | + { | ||
| 57 | + var config = parameter==null?null:((parameter as Menu.ExecutorParameter).GetConfig<BackupPackageManagerXmlProcessor>()); | ||
| 58 | + var args = parameter == null ? null : ((parameter as Menu.ExecutorParameter).Args); | ||
| 59 | + | ||
| 60 | + var dir1= CommandLine.GetCommandLineArgument(args, CLP.Module.BackupPackageManager.Functions.CMD_DIR1); | ||
| 61 | + var dir2 = CommandLine.GetCommandLineArgument(args, CLP.Module.BackupPackageManager.Functions.CMD_DIR2); | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + string rootWORKING = ColorConsole.ReadLine("Enter path to WORKING INSTALLATION directory:", defaultvalue: dir1 ?? "", required: true); //@"C:\Path\To\Folder1"; | ||
| 65 | + string rootUPGRADE = ColorConsole.ReadLine("Enter path to UPGRADE INSTALLATION directory:", defaultvalue: dir1 ?? "", required: true); //@"C:\Path\To\Folder2"; | ||
| 66 | + string searchpatterncsvlist = ColorConsole.ReadLine("Enter search pattern (csv list):", defaultvalue: "*.dll,*.exe", required: true); //@"C:\Path\To\Folder2"; | ||
| 67 | + | ||
| 68 | + rootWORKING = rootWORKING + @"\"; rootWORKING.Replace(@"/", @"\").Replace(@"\\", @"\"); | ||
| 69 | + rootUPGRADE = rootUPGRADE + @"\"; rootUPGRADE.Replace(@"/", @"\").Replace(@"\\", @"\"); | ||
| 70 | + | ||
| 71 | + ColorConsole.WriteLine("Comparing folders..."); | ||
| 72 | + ColorConsole.WriteLine($" WORKING INSTALLATION: {rootWORKING}"); | ||
| 73 | + ColorConsole.WriteLine($" UPGRADE INSTALLATION: {rootUPGRADE}"); | ||
| 74 | + ColorConsole.WriteLine($" Search patterns: {searchpatterncsvlist}"); | ||
| 75 | + ColorConsole.WriteLine(); | ||
| 76 | + | ||
| 77 | + | ||
| 78 | + var folder1Files = GetFilesWithRelativePaths(rootWORKING, searchpatterncsvlist); | ||
| 79 | + var folder2Files = GetFilesWithRelativePaths(rootUPGRADE, searchpatterncsvlist); | ||
| 80 | + | ||
| 81 | + var allKeys = new HashSet<string>(folder1Files.Keys); | ||
| 82 | + allKeys.UnionWith(folder2Files.Keys); | ||
| 83 | + | ||
| 84 | + var savedcursortop = Console.CursorTop; | ||
| 85 | + Console.WriteLine(); | ||
| 86 | + var actualcursortop = Console.CursorTop; | ||
| 87 | + var numberofprocessedfiles = 0; | ||
| 88 | + var upgradefiles = new Dictionary<string, CompareDirectoriesActions>(); | ||
| 89 | + foreach (var relativePath in allKeys.OrderBy(p => p)) | ||
| 90 | + { | ||
| 91 | + numberofprocessedfiles++; | ||
| 92 | + if (numberofprocessedfiles < 25) | ||
| 93 | + { | ||
| 94 | + actualcursortop = Console.CursorTop; | ||
| 95 | + ColorConsole.SetCursorPosition(0, savedcursortop); ColorConsole.Write(relativePath, suffix: new string(' ', 20)); | ||
| 96 | + ColorConsole.SetCursorPosition(0, actualcursortop); | ||
| 97 | + } | ||
| 98 | + bool inWORKFolder = folder1Files.TryGetValue(relativePath, out string file1); | ||
| 99 | + bool inUPGRADEFolder = folder2Files.TryGetValue(relativePath, out string file2); | ||
| 100 | + | ||
| 101 | + if (inWORKFolder && inUPGRADEFolder) | ||
| 102 | + { | ||
| 103 | + if (!FilesAreEqual(file1, file2, out string difftext)) | ||
| 104 | + { | ||
| 105 | + //ColorConsole.WriteLine($"DIFFERENT ({difftext}): {relativePath}", ConsoleColor.Yellow); | ||
| 106 | + ColorConsole.WriteLine($"< {relativePath} ({difftext}):", ConsoleColor.Yellow); | ||
| 107 | + upgradefiles.Add(relativePath, CompareDirectoriesActions.CopyFROMUPGRADE); | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + else if (inWORKFolder) | ||
| 111 | + { | ||
| 112 | + //ColorConsole.WriteLine($"ONLY IN Folder1: {relativePath}", ConsoleColor.Yellow); | ||
| 113 | + ColorConsole.WriteLine($"-- {relativePath}", ConsoleColor.Yellow); | ||
| 114 | + upgradefiles.Add(relativePath, CompareDirectoriesActions.DeleteINWORKING); | ||
| 115 | + } | ||
| 116 | + else if (inUPGRADEFolder) | ||
| 117 | + { | ||
| 118 | + //ColorConsole.WriteLine($"ONLY IN Folder2: {relativePath}", ConsoleColor.Yellow); | ||
| 119 | + ColorConsole.WriteLine($"<< {relativePath}", ConsoleColor.Yellow); | ||
| 120 | + upgradefiles.Add(relativePath, CompareDirectoriesActions.CopyFROMUPGRADE); | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + ColorConsole.WriteLine(); | ||
| 124 | + string movefiles = ColorConsole.ReadLine("Do You want to upgrade WORKING INSTALLATION with UPGRADE INSTALLATION:",validitylist: new List<string>{"yes","no","YES","NO", }, defaultvalue: "no", required: true); //@"C:\Path\To\Folder1"; | ||
| 125 | + if (movefiles.ToUpper() == "YES") | ||
| 126 | + { | ||
| 127 | + foreach (var uf in upgradefiles) | ||
| 128 | + { | ||
| 129 | + if (uf.Value == CompareDirectoriesActions.CopyFROMUPGRADE) { File.Copy(Path.Combine(rootUPGRADE, uf.Key), Path.Combine(rootWORKING, uf.Key)); } | ||
| 130 | + else if (uf.Value == CompareDirectoriesActions.DeleteINWORKING) { File.Delete(Path.Combine(rootWORKING,uf.Key)); } | ||
| 131 | + } | ||
| 132 | + } | ||
| 133 | + return o; | ||
| 134 | + } | ||
| 135 | + private enum CompareDirectoriesActions { CopyFROMUPGRADE, DeleteINWORKING,} | ||
| 136 | + private static Dictionary<string, string> GetFilesWithRelativePaths(string root,string searchpattern="*") | ||
| 137 | + { | ||
| 138 | + var searchpatternlist = searchpattern.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); | ||
| 139 | + List<string> files = new List<string>() { }; | ||
| 140 | + foreach (var sp in searchpatternlist) | ||
| 141 | + { | ||
| 142 | + files.AddRange(Directory.GetFiles(root, sp, SearchOption.AllDirectories)); | ||
| 143 | + } | ||
| 144 | + var dict = new Dictionary<string, string>(); | ||
| 145 | + foreach (var file in files) | ||
| 146 | + { | ||
| 147 | + string relativePath = GetRelativePath(root, file); | ||
| 148 | + dict[relativePath] = file; | ||
| 149 | + } | ||
| 150 | + return dict; | ||
| 151 | + } | ||
| 152 | + /// <summary> | ||
| 153 | + /// Creates a relative path from one file or folder to another. | ||
| 154 | + /// </summary> | ||
| 155 | + /// <param name="fromPath">Contains the directory that defines the start of the relative path.</param> | ||
| 156 | + /// <param name="toPath">Contains the path that defines the endpoint of the relative path.</param> | ||
| 157 | + /// <returns>The relative path from the start directory to the end path or <c>toPath</c> if the paths are not related.</returns> | ||
| 158 | + /// <exception cref="ArgumentNullException"></exception> | ||
| 159 | + /// <exception cref="UriFormatException"></exception> | ||
| 160 | + /// <exception cref="InvalidOperationException"></exception> | ||
| 161 | + public static string GetRelativePath(String fromPath, String toPath) | ||
| 162 | + { | ||
| 163 | + if (String.IsNullOrEmpty(fromPath)) throw new ArgumentNullException("fromPath"); | ||
| 164 | + if (String.IsNullOrEmpty(toPath)) throw new ArgumentNullException("toPath"); | ||
| 165 | + | ||
| 166 | + Uri fromUri = new Uri(fromPath); | ||
| 167 | + Uri toUri = new Uri(toPath); | ||
| 168 | + | ||
| 169 | + if (fromUri.Scheme != toUri.Scheme) { return toPath; } // path can't be made relative. | ||
| 170 | + | ||
| 171 | + Uri relativeUri = fromUri.MakeRelativeUri(toUri); | ||
| 172 | + String relativePath = Uri.UnescapeDataString(relativeUri.ToString()); | ||
| 173 | + | ||
| 174 | + if (toUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase)) | ||
| 175 | + { | ||
| 176 | + relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + return relativePath; | ||
| 180 | + } | ||
| 181 | + private static bool FilesAreEqual(string WORKINGfilePath, string UPGRADEfilePath,out string differencetext) | ||
| 182 | + { | ||
| 183 | + differencetext = null; | ||
| 184 | + var fiW = new FileInfo(WORKINGfilePath); | ||
| 185 | + var fiU = new FileInfo(UPGRADEfilePath); | ||
| 186 | + | ||
| 187 | + var fvW = FileVersionInfo.GetVersionInfo(WORKINGfilePath); | ||
| 188 | + var fvU = FileVersionInfo.GetVersionInfo(UPGRADEfilePath); | ||
| 189 | + var fvW1=GetVersionNumber(fvW, out string fvW2); | ||
| 190 | + var fvU1 = GetVersionNumber(fvU, out string fvU2); | ||
| 191 | + var fveresiondifftext = "";// $" {fvW1}<>{fvU1};{fvW2}<>{fvU2}"; | ||
| 192 | + var pvW1 = GetVersionNumber(fvW, out string pvW2,true); | ||
| 193 | + var pvU1 = GetVersionNumber(fvU, out string pvU2,true); | ||
| 194 | + var pveresiondifftext = "";// $" {pvW1}<>{pvU1};{pvW2}<>{pvU2}"; | ||
| 195 | + if (fvW.FileVersion != fvU.FileVersion) { string oldertext = fvW1 > fvU1 ? "DOWNGRADE":"UPGRADE"; differencetext = $"{oldertext} FileVersion: {fveresiondifftext} {fvW.FileVersion} <--> {fvU.FileVersion}"; return false; } | ||
| 196 | + if (fvW.ProductVersion != fvU.ProductVersion) { string oldertext = pvW1 > pvU1 ? "DOWNGRADE" : "UPGRADE"; differencetext = $"{oldertext} ProductVersion: {pveresiondifftext} {fvW.ProductVersion} <--> {fvU.ProductVersion}"; return false; } | ||
| 197 | + //if (fi1.CreationTime != fi2.CreationTime) return false; | ||
| 198 | + //if (fi1.LastWriteTimeUtc != fi2.LastWriteTimeUtc) { differencetext = "LastWriteTimeUTC"; return false; } | ||
| 199 | + if (fiW.Length != fiU.Length) { string oldertext = fiW.Length > fiU.Length?"DOWNSIZE":"UPSIZE"; differencetext = $"Length: {oldertext} {fiW.Length} <--> {fiU.Length}"; return false; } | ||
| 200 | + using (var sha256 = SHA256.Create()) | ||
| 201 | + using (var stream1 = File.OpenRead(WORKINGfilePath)) | ||
| 202 | + using (var stream2 = File.OpenRead(UPGRADEfilePath)) | ||
| 203 | + { | ||
| 204 | + var hash1 = sha256.ComputeHash(stream1); | ||
| 205 | + var hash2 = sha256.ComputeHash(stream2); | ||
| 206 | + | ||
| 207 | + if (!hash1.SequenceEqual(hash2)) { differencetext = "Hash/Content"; return false; } | ||
| 208 | + } | ||
| 209 | + return true; | ||
| 210 | + } | ||
| 211 | + private static long GetVersionNumber(FileVersionInfo vi,out string vt,bool useproductversion=false) | ||
| 212 | + { | ||
| 213 | + vt = useproductversion | ||
| 214 | + ? $"{vi.ProductMajorPart}.{vi.ProductMinorPart}.{vi.ProductBuildPart}.{vi.ProductPrivatePart}" | ||
| 215 | + : $"{vi.FileMajorPart}.{vi.FileMinorPart}.{vi.FileBuildPart}.{vi.FilePrivatePart}"; | ||
| 216 | + long numberbase = 10000; | ||
| 217 | + return useproductversion | ||
| 218 | + ? vi.ProductMajorPart * numberbase * numberbase * numberbase + vi.ProductMinorPart * numberbase * numberbase + vi.ProductBuildPart * numberbase + vi.ProductPrivatePart | ||
| 219 | + : vi.FileMajorPart * numberbase * numberbase * numberbase + vi.FileMinorPart * numberbase * numberbase + vi.FileBuildPart * numberbase + vi.FilePrivatePart; | ||
| 220 | + } | ||
| 221 | + private static object CreateBackupPackage(object parameter, object o) | ||
| 54 | { | 222 | { |
| 55 | var config = (parameter as Menu.ExecutorParameter).GetConfig< BackupPackageManagerXmlProcessor>(); | 223 | var config = (parameter as Menu.ExecutorParameter).GetConfig< BackupPackageManagerXmlProcessor>(); |
| 56 | var args = (parameter as Menu.ExecutorParameter).Args; | 224 | var args = (parameter as Menu.ExecutorParameter).Args; |
Vrh.Log4Pro.MaintenanceConsole/Properties/AssemblyInfo.cs
| @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; | @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; | ||
| 32 | // You can specify all the values or you can default the Build and Revision Numbers | 32 | // You can specify all the values or you can default the Build and Revision Numbers |
| 33 | // by using the '*' as shown below: | 33 | // by using the '*' as shown below: |
| 34 | // [assembly: AssemblyVersion("1.0.*")] | 34 | // [assembly: AssemblyVersion("1.0.*")] |
| 35 | -[assembly: AssemblyVersion("1.33.0.0")] | ||
| 36 | -[assembly: AssemblyFileVersion("1.33.0.0")] | 35 | +[assembly: AssemblyVersion("1.34.0.0")] |
| 36 | +[assembly: AssemblyFileVersion("1.34.0.0")] |