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 | 288 | public static class Functions |
289 | 289 | { |
290 | 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 | 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 | 303 | public static class SQLDataBaseManager |
298 | 304 | { |
299 | 305 | public const string KEY = "SQL"; | ... | ... |
Vrh.Log4Pro.MaintenanceConsole/Manager - BackupPackageManager.cs
... | ... | @@ -22,6 +22,7 @@ using Vrh.XmlProcessing; |
22 | 22 | using VRH.Common; |
23 | 23 | using System.Xml.Linq; |
24 | 24 | using System.Text.RegularExpressions; |
25 | +using System.Security.Cryptography; | |
25 | 26 | |
26 | 27 | namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS |
27 | 28 | { |
... | ... | @@ -42,7 +43,8 @@ namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS |
42 | 43 | |
43 | 44 | var menufunctions = new Menu("Manage Backup Packages", "Select the management function!") |
44 | 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 | 48 | .SetMenuHeaderDisplayer(BackupPackageListDisplayer); |
47 | 49 | menufunctions.ExecuteMenu(functionkey); |
48 | 50 | return o2; |
... | ... | @@ -50,7 +52,173 @@ namespace Vrh.Log4Pro.MaintenanceConsole.BackupPackageManagerNS |
50 | 52 | #endregion Execute |
51 | 53 | |
52 | 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 | 223 | var config = (parameter as Menu.ExecutorParameter).GetConfig< BackupPackageManagerXmlProcessor>(); |
56 | 224 | var args = (parameter as Menu.ExecutorParameter).Args; | ... | ... |
Vrh.Log4Pro.MaintenanceConsole/Properties/AssemblyInfo.cs
... | ... | @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; |
32 | 32 | // You can specify all the values or you can default the Build and Revision Numbers |
33 | 33 | // by using the '*' as shown below: |
34 | 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")] | ... | ... |