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")] |