Check-in [16163e0aca]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added options for archive and backup directories.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | develop
Files: files | file ages | folders
SHA1: 16163e0aca24d55ae12dc0fa8646f0419ef9be1d
User & Date: tinus 2018-03-21 19:53:37
Context
2018-03-21
20:08
Bugfix: FileInfo.MoveTo also changes the FileInfo's FullName. :-) check-in: bfd001af76 user: tinus tags: develop
19:53
Added options for archive and backup directories. check-in: 16163e0aca user: tinus tags: develop
2018-03-12
02:28
Various improvements to ZTUpdater. Got rid of Html2Markdown, ported own poor man’s HtmlToText to C#, which appears to work better for this forum. check-in: 56d8711cc9 user: tinus tags: develop
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ZTUpdater/Program.cs.

8
9
10
11
12
13
14




15
16
17



18
19
20
21






22
23

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39






40
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62




63
64
65
66
67
68
69
70
71
72
73
74
75
76
77


    class Program
    {
        [STAThread]
        static int Main(string[] args)
        {
            try
            {




                foreach (var arg in args)
                {
                    if (arg == "/?" || arg.StartsWith("/h", true, CultureInfo.CurrentCulture))



                    {
                        ShowHelp();
                        return 0;
                    }






                }


                var Updater = new ZTWUpdater()
                {
                    OnLog = WriteLog
                };
                if (Updater.ZTreeHome == null)
                {
                    // ask for folder (using dialog?)
                    var Dialog = new System.Windows.Forms.FolderBrowserDialog
                    {
                        SelectedPath = @"C:\ZTree",
                        ShowNewFolderButton = false,
                        Description = "Please select the folder where ZTreeWin is installed"
                    };
                    if (Dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                       Updater.ZTreeHome = Dialog.SelectedPath;
                }






                var UpdateTask = Updater.Update();
                UpdateTask.Wait();

                return UpdateTask.Result ? 0 : 1;
            }
            catch (Exception ex)
            {
                var BackupColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.Error.WriteLine(ex.Message);
                Console.ForegroundColor = BackupColor;
                return 255;
            }
        }

        private static void ShowHelp()
        {
            throw new NotImplementedException();
        }

        private static Dictionary<TraceLevel, ConsoleColor> _levelColors = new Dictionary<TraceLevel, ConsoleColor>();

        private static void WriteLog(string message, TraceLevel level)
        {




            if (_levelColors.Count == 0)
            {
                _levelColors.Add(TraceLevel.Verbose, ConsoleColor.DarkGray);
                _levelColors.Add(TraceLevel.Warning, ConsoleColor.Yellow);
                _levelColors.Add(TraceLevel.Error, ConsoleColor.Red);
            }
            var Output = level >= TraceLevel.Warning ? Console.Error : Console.Out;
            var BackupColor = Console.ForegroundColor;
            if (_levelColors.TryGetValue(level, out var Color))
                Console.ForegroundColor = Color;
            Output.WriteLine(message);
            Console.ForegroundColor = BackupColor;
        }
    }
}









>
>
>
>


<
>
>
>




>
>
>
>
>
>


>


|













>
>
>
>
>
>


>
|





|












|

>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
8
9
10
11
12
13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    class Program
    {
        [STAThread]
        static int Main(string[] args)
        {
            try
            {
                // Read the command-line options
                var MinimumLevel = TraceLevel.Info;
                string OptName = null;
                var Options = new Dictionary<string, string>();
                foreach (var arg in args)
                {

                    if (OptName != null)
                        Options.Add(OptName, arg);
                    else if (arg == "/?" || arg == "/h" || arg == "/help")
                    {
                        ShowHelp();
                        return 0;
                    }
                    else if (arg == "/v" || arg == "/verbose")
                        MinimumLevel = TraceLevel.Verbose;
                    else if (arg == "/b" || arg == "/backup")
                        OptName = "backup";
                    else if (arg == "/a" || arg == "/archive")
                        OptName = "archive";
                }

                // Initialize the updater component
                var Updater = new ZTWUpdater()
                {
                    OnLog = WriteLog(MinimumLevel)
                };
                if (Updater.ZTreeHome == null)
                {
                    // ask for folder (using dialog?)
                    var Dialog = new System.Windows.Forms.FolderBrowserDialog
                    {
                        SelectedPath = @"C:\ZTree",
                        ShowNewFolderButton = false,
                        Description = "Please select the folder where ZTreeWin is installed"
                    };
                    if (Dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                       Updater.ZTreeHome = Dialog.SelectedPath;
                }
                if (Options.TryGetValue("archive", out var Value))
                    Updater.ArchiveDir = new System.IO.DirectoryInfo(Value);
                else if (Options.TryGetValue("backup", out Value))
                    Updater.BackupDir = new System.IO.DirectoryInfo(Value);

                // Perform the actual update
                var UpdateTask = Updater.Update();
                UpdateTask.Wait();
                WriteLog(MinimumLevel)($"{UpdateTask.Result} files updated.", TraceLevel.Info);
                return UpdateTask.Result > 0 ? 0 : 1;
            }
            catch (Exception ex)
            {
                var BackupColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.Error.WriteLine(ex.ToString());
                Console.ForegroundColor = BackupColor;
                return 255;
            }
        }

        private static void ShowHelp()
        {
            throw new NotImplementedException();
        }

        private static Dictionary<TraceLevel, ConsoleColor> _levelColors = new Dictionary<TraceLevel, ConsoleColor>();

        private static Action<string, TraceLevel> WriteLog(TraceLevel minimumLevel)
        {
            return (message, level) =>
            {
                if (level <= minimumLevel)
                {
                    if (_levelColors.Count == 0)
                    {
                        _levelColors.Add(TraceLevel.Verbose, ConsoleColor.DarkGray);
                        _levelColors.Add(TraceLevel.Warning, ConsoleColor.Yellow);
                        _levelColors.Add(TraceLevel.Error, ConsoleColor.Red);
                    }
                    var Output = level >= TraceLevel.Warning ? Console.Error : Console.Out;
                    var BackupColor = Console.ForegroundColor;
                    if (_levelColors.TryGetValue(level, out var Color))
                        Console.ForegroundColor = Color;
                    Output.WriteLine(message);
                    Console.ForegroundColor = BackupColor;
                }
            };
        }
    }
}

Changes to ZTUpdater/ZTUpdater.cs.

11
12
13
14
15
16
17



18
19
20
21
22
23
24
25
...
102
103
104
105
106
107
108


109

110
111
112
113
114
115
116
...
141
142
143
144
145
146
147
148
149
150
151
152
153


154
155
156
157
158
159

160
161
162
163
164
165
166
167
168
169
170
171
...
194
195
196
197
198
199
200
201
202
203
204
205
206

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223





224












225
226
227
228

229















230
231
232
233
234
235
236

namespace ZTUpdater
{
    public class ZTWUpdater
    {
        public Action<string, TraceLevel> OnLog = (msg, level) => Debug.WriteLine(msg, level.ToString());




        public string Executable { get; set; } = Environment.Is64BitOperatingSystem ? "ZTW64.exe" : "ZTW.exe";
        public string CurrentVersion { get; private set; }
        public string LatestVersion { get; private set; }
        public string WhatsNew { get; private set; }

        private string _ZTreeHome;

        public ZTWUpdater() : this(GetZTreeHome())
................................................................................
                }

                // Extract the version and the post’s ID
                string PostID = Match.Groups[1].Value;
                LatestVersion = Match.Groups[2].Value;
                Log($"Found announcement for version {LatestVersion}.");
                if (!IsVersionNewer(LatestVersion, CurrentVersion))


                    return null;


                // get the announcement post
                Response = await Client.GetAsync($"http://www.ztw3.com/forum/forum_entry.php?id={PostID}");
                Html = await Response.Content.ReadAsStringAsync();

                // extract the "What’s New"
                Match = _rexWhatsNew.Match(Html);
................................................................................
            }
        }

        public bool IsVersionNewer(string newVersion, string oldVersion)
        {
            var New = new Version(newVersion);
            var Old = new Version(oldVersion);
            return newVersion.CompareTo(oldVersion) > 0;
        }

        public async Task<bool> Update()
        {
            Log($"ZTreeWin version {CurrentVersion} located in \"{ZTreeHome}\".", TraceLevel.Info);



            var DownloadUri = await GetUriLatestVersion();
            if (DownloadUri == null)
                return false;

            // Prepare to save the file in the user’s Downloads folder

            string OrgZipFile = DownloadUri.AbsolutePath;
            int Pos = OrgZipFile.LastIndexOf("/");
            if (Pos > -1)
                OrgZipFile = OrgZipFile.Substring(Pos + 1);
            OrgZipFile = Path.Combine(KnownFolders.Downloads.Path, OrgZipFile);

            string ZipFile = OrgZipFile;
            string Extension = Path.GetExtension(ZipFile);
            string Base = ZipFile.Substring(0, ZipFile.Length - Extension.Length);
            int Counter = 0;
            while (File.Exists(ZipFile))
            {
................................................................................
                {
                    File.Delete(ZipFile);
                    ZipFile = OrgZipFile;
                }
            }

            // Perform the update based on the downloaded file
            UpdateFromFile(ZipFile);
            return true;
        }

        public void UpdateFromFile(string file)
        {

            Log($"Extracting files...");
            var Zip = ZipFile.OpenRead(file);
            foreach(var Entry in Zip.Entries)
            {
                var File = new FileInfo(Path.Combine(ZTreeHome, Entry.FullName.Replace('/', '\\')));
                if (File.Exists)
                {
                    if (Identical(Entry, File))
                    {
                        Log($"\t{Entry.FullName}\tidentical to existing file; skipping.");
                        continue;
                    }

                    // rename as backup for current version
                    var Extension = File.Extension;
                    var BackupName = File.FullName.Substring(0, File.FullName.Length - Extension.Length) + "-v" + CurrentVersion + Extension;
                    Log($"\t{Entry.FullName}\tbacking up existing file.");





                    File.MoveTo(BackupName);












                }

                Log($"\t{Entry.FullName}\textracting...");
                Entry.ExtractToFile(File.FullName);

            }















        }

        private bool Identical(ZipArchiveEntry Entry, FileInfo File)
        {
            if (Entry.Length != File.Length)
                return false;








>
>
>
|







 







>
>

>







 







|


|


>
>



|


>




|







 







|
<


|

>













|
|
<

>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>




>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
...
203
204
205
206
207
208
209
210

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

namespace ZTUpdater
{
    public class ZTWUpdater
    {
        public Action<string, TraceLevel> OnLog = (msg, level) => Debug.WriteLine(msg, level.ToString());

        public DirectoryInfo ArchiveDir { get; set; }
        public DirectoryInfo BackupDir { get; set; }

        public string Executable { get; private set; } = Environment.Is64BitOperatingSystem ? "ZTW64.exe" : "ZTW.exe";
        public string CurrentVersion { get; private set; }
        public string LatestVersion { get; private set; }
        public string WhatsNew { get; private set; }

        private string _ZTreeHome;

        public ZTWUpdater() : this(GetZTreeHome())
................................................................................
                }

                // Extract the version and the post’s ID
                string PostID = Match.Groups[1].Value;
                LatestVersion = Match.Groups[2].Value;
                Log($"Found announcement for version {LatestVersion}.");
                if (!IsVersionNewer(LatestVersion, CurrentVersion))
                {
                    Log("All up-to-date.", TraceLevel.Info);
                    return null;
                }

                // get the announcement post
                Response = await Client.GetAsync($"http://www.ztw3.com/forum/forum_entry.php?id={PostID}");
                Html = await Response.Content.ReadAsStringAsync();

                // extract the "What’s New"
                Match = _rexWhatsNew.Match(Html);
................................................................................
            }
        }

        public bool IsVersionNewer(string newVersion, string oldVersion)
        {
            var New = new Version(newVersion);
            var Old = new Version(oldVersion);
            return newVersion.CompareTo(oldVersion) >= 0;
        }

        public async Task<int> Update()
        {
            Log($"ZTreeWin version {CurrentVersion} located in \"{ZTreeHome}\".", TraceLevel.Info);
            if (!Directory.Exists(ZTreeHome))
                throw new DirectoryNotFoundException($"Directory \"{ZTreeHome}\" not found");

            var DownloadUri = await GetUriLatestVersion();
            if (DownloadUri == null)
                return 0;

            // Prepare to save the file in the user’s Downloads folder
            string Folder = (ArchiveDir ?? BackupDir)?.FullName ?? KnownFolders.Downloads.Path;
            string OrgZipFile = DownloadUri.AbsolutePath;
            int Pos = OrgZipFile.LastIndexOf("/");
            if (Pos > -1)
                OrgZipFile = OrgZipFile.Substring(Pos + 1);
            OrgZipFile = Path.Combine(Folder, OrgZipFile);

            string ZipFile = OrgZipFile;
            string Extension = Path.GetExtension(ZipFile);
            string Base = ZipFile.Substring(0, ZipFile.Length - Extension.Length);
            int Counter = 0;
            while (File.Exists(ZipFile))
            {
................................................................................
                {
                    File.Delete(ZipFile);
                    ZipFile = OrgZipFile;
                }
            }

            // Perform the update based on the downloaded file
            return UpdateFromFile(ZipFile);

        }

        public int UpdateFromFile(string file)
        {
            int NumFiles = 0;
            Log($"Extracting files...");
            var Zip = ZipFile.OpenRead(file);
            foreach(var Entry in Zip.Entries)
            {
                var File = new FileInfo(Path.Combine(ZTreeHome, Entry.FullName.Replace('/', '\\')));
                if (File.Exists)
                {
                    if (Identical(Entry, File))
                    {
                        Log($"\t{Entry.FullName}\tidentical to existing file; skipping.");
                        continue;
                    }

                    // Try moving to version-based folder first; only if that doesn't work, try to rename
                    //  to a version-based file name in the same folder.

                    Log($"\t{Entry.FullName}\tbacking up existing file.");
                    try
                    {
                        var BackupName = VersionBasedFolder(File);
                        try
                        {
                            File.MoveTo(BackupName);
                        }
                        catch (Exception ex)
                        {
                            Log($"\t{Entry.FullName}\tFirst attempt: {ex.Message.Trim()}");
                            BackupName = VersionBasedFilename(File);
                            File.MoveTo(BackupName);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log($"\t{Entry.FullName}\tBackup failed: {ex.Message.Trim()}", TraceLevel.Warning);
                    }
                }

                Log($"\t{Entry.FullName}\textracting...");
                Entry.ExtractToFile(File.FullName);
                NumFiles++;
            }
            return NumFiles;
        }

        private string VersionBasedFolder(FileInfo File)
        {
            var SourceDir = new DirectoryInfo(ZTreeHome);
            var TargetDir = BackupDir ?? SourceDir.CreateSubdirectory($@"Backup");
            TargetDir = TargetDir.CreateSubdirectory(CurrentVersion);
            return Path.Combine(TargetDir.FullName, File.FullName.Substring(SourceDir.FullName.Length + 1));
        }

        private string VersionBasedFilename(FileInfo File)
        {
            var Extension = File.Extension;
            return File.FullName.Substring(0, File.FullName.Length - Extension.Length) + "-v" + CurrentVersion + Extension;
        }

        private bool Identical(ZipArchiveEntry Entry, FileInfo File)
        {
            if (Entry.Length != File.Length)
                return false;