source: branches/eraser6/Eraser/UpdateForm.cs @ 516

Revision 516, 23.8 KB checked in by lowjoel, 6 years ago (diff)

-Have error messages persist throughout the update session
-Have a Dictionary mapping the UpdateManager?.Update object to the various data: ListViewItem? and Exception
-Fixed a progress calculation bug when a WebException? is thrown and caught during downloading

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Data;
26using System.Drawing;
27using System.Text;
28using System.Windows.Forms;
29using System.Net;
30using System.Reflection;
31using System.IO;
32using System.Xml;
33using Eraser.Util;
34using System.Net.Cache;
35
36namespace Eraser
37{
38    public partial class UpdateForm : Form
39    {
40        /// <summary>
41        /// Constructor.
42        /// </summary>
43        public UpdateForm()
44        {
45            InitializeComponent();
46
47            updates = new UpdateManager();
48            updateListDownloader.RunWorkerAsync();
49        }
50
51        #region Update List retrieval
52        /// <summary>
53        /// Downloads and parses the list of updates available for this client.
54        /// </summary>
55        /// <param name="sender">The object triggering this event/</param>
56        /// <param name="e">Event argument.</param>
57        private void updateListDownloader_DoWork(object sender, DoWorkEventArgs e)
58        {
59            try
60            {
61                updates.OnProgressEvent += updateListDownloader_ProgressChanged;
62                updates.GetUpdates();
63            }
64            finally
65            {
66                updates.OnProgressEvent -= updateListDownloader_ProgressChanged;
67            }
68        }
69
70        /// <summary>
71        /// Called when progress has been made in the update list download.
72        /// </summary>
73        /// <param name="sender">The object triggering this event/</param>
74        /// <param name="e">Event argument.</param>
75        private void updateListDownloader_ProgressChanged(object sender, UpdateManager.ProgressEventArgs e)
76        {
77            if (InvokeRequired)
78            {
79                Invoke(new UpdateManager.ProgressEventFunction(updateListDownloader_ProgressChanged),
80                    sender, e);
81                return;
82            }
83
84            progressPb.Style = ProgressBarStyle.Continuous;
85            progressPb.Value = (int)(e.OverallProgressPercentage * 100);
86            progressLbl.Text = e.Message;
87
88            if (progressPb.Value == 100)
89                progressProgressLbl.Text = S._("Processing update list...");
90        }
91
92        /// <summary>
93        /// Displays the parsed updates on the updates list view, filtering and displaying
94        /// only those relevant to the current system's architecture.
95        /// </summary>
96        /// <param name="sender">The object triggering this event/</param>
97        /// <param name="e">Event argument.</param>
98        private void updateListDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
99        {
100            //The Error property will normally be null unless there are errors during the download.
101            if (e.Error != null)
102            {
103                MessageBox.Show(this, e.Error.Message, S._("Eraser"),
104                    MessageBoxButtons.OK, MessageBoxIcon.Error);
105                Close();
106                return;
107            }
108
109            progressPanel.Visible = false;
110
111            updatesPanel.Show();
112            updatesPanel.Visible = true;
113            updatesPanel.ResumeLayout();
114
115            //Get a list of translatable categories (this will change as more categories
116            //are added)
117            Dictionary<string, string> updateCategories = new Dictionary<string, string>();
118            updateCategories.Add("updates", S._("Updates"));
119            updateCategories.Add("plugins", S._("Plugins"));
120
121            //Only include those whose architecture is compatible with ours.
122            List<string> compatibleArchs = new List<string>();
123            {
124                //any is always compatible.
125                compatibleArchs.Add("any");
126
127                KernelAPI.SYSTEM_INFO info = new KernelAPI.SYSTEM_INFO();
128                KernelAPI.GetSystemInfo(out info);
129                switch (info.processorArchitecture)
130                {
131                    case KernelAPI.SYSTEM_INFO.ProcessorArchitecture.PROCESSOR_ARCHITECTURE_AMD64:
132                        compatibleArchs.Add("x64");
133                        break;
134
135                    case KernelAPI.SYSTEM_INFO.ProcessorArchitecture.PROCESSOR_ARCHITECTURE_IA64:
136                        compatibleArchs.Add("ia64");
137                        break;
138
139                    case KernelAPI.SYSTEM_INFO.ProcessorArchitecture.PROCESSOR_ARCHITECTURE_INTEL:
140                        compatibleArchs.Add("x86");
141                        break;
142                }
143            }
144
145            foreach (string key in updates.Categories)
146            {
147                ListViewGroup group = new ListViewGroup(updateCategories.ContainsKey(key) ?
148                    updateCategories[key] : key);
149                updatesLv.Groups.Add(group);
150
151                foreach (UpdateManager.Update update in updates[key])
152                {
153                    //Skip if this update won't work on our current architecture.
154                    if (compatibleArchs.IndexOf(update.Architecture) == -1)
155                        continue;
156
157                    ListViewItem item = new ListViewItem(update.Name);
158                    item.SubItems.Add(update.Version.ToString());
159                    item.SubItems.Add(update.Publisher);
160                    item.SubItems.Add(update.FileSize.ToString());
161
162                    item.Tag = update;
163                    item.Group = group;
164                    item.Checked = true;
165
166                    updatesLv.Items.Add(item);
167                    uiUpdates.Add(update, new UpdateData(update, item));
168                }
169            }
170        }
171        #endregion
172
173        #region Update downloader
174        /// <summary>
175        /// Handles the Install button click; fetches and installs the updates selected.
176        /// </summary>
177        /// <param name="sender">The object triggering this event/</param>
178        /// <param name="e">Event argument.</param>
179        private void updatesBtn_Click(object sender, EventArgs e)
180        {
181            updatesPanel.Visible = false;
182            downloadingPnl.Show();
183            List<UpdateManager.Update> updatesToInstall =
184                new List<UpdateManager.Update>();
185
186            //Collect the items that need to be installed
187            foreach (ListViewItem item in updatesLv.Items)
188                if (item.Checked)
189                {
190                    item.Remove();
191                    item.SubItems.RemoveAt(1);
192                    item.SubItems.RemoveAt(1);
193                    downloadingLv.Items.Add(item);
194
195                    updatesToInstall.Add((UpdateManager.Update)item.Tag);
196                }
197                else
198                    uiUpdates.Remove((UpdateManager.Update)item.Tag);
199
200            //Then run the thread.
201            downloader.RunWorkerAsync(updatesToInstall);
202        }
203
204        /// <summary>
205        /// Background thread to do the downloading and installing of updates.
206        /// </summary>
207        /// <param name="sender">The object triggering this event/</param>
208        /// <param name="e">Event argument.</param>
209        private void downloader_DoWork(object sender, DoWorkEventArgs e)
210        {
211            try
212            {
213                updates.OnProgressEvent += downloader_ProgressChanged;
214                object downloadedUpdates = updates.DownloadUpdates((List<UpdateManager.Update>)e.Argument);
215                e.Result = downloadedUpdates;
216            }
217            finally
218            {
219                updates.OnProgressEvent -= downloader_ProgressChanged;
220            }
221        }
222
223        /// <summary>
224        /// Handles the download progress changed event.
225        /// </summary>
226        /// <param name="sender">The object triggering this event/</param>
227        /// <param name="e">Event argument.</param>
228        private void downloader_ProgressChanged(object sender, UpdateManager.ProgressEventArgs e)
229        {
230            if (InvokeRequired)
231            {
232                Invoke(new UpdateManager.ProgressEventFunction(downloader_ProgressChanged),
233                    sender, e);
234                return;
235            }
236
237            UpdateData update = uiUpdates[(UpdateManager.Update)e.UserState];
238            int amountLeft = (int)((1 - e.ProgressPercentage) * update.Update.FileSize);
239
240            if (e is UpdateManager.ProgressErrorEventArgs)
241            {
242                update.Error = ((UpdateManager.ProgressErrorEventArgs)e).Exception;
243                update.LVItem.ImageIndex = 3;
244                update.LVItem.SubItems[1].Text = S._("Error");
245                update.LVItem.ToolTipText = update.Error.Message;
246            }
247            else
248            {
249                if (amountLeft == 0)
250                {
251                    update.LVItem.ImageIndex = -1;
252                    update.LVItem.SubItems[1].Text = S._("Downloaded");
253                }
254                else
255                {
256                    update.LVItem.ImageIndex = 0;
257                    update.LVItem.SubItems[1].Text = amountLeft.ToString();
258                }
259            }
260
261            downloadingItemLbl.Text = e.Message;
262            downloadingItemPb.Value = (int)(e.ProgressPercentage * 100);
263            downloadingOverallPb.Value = (int)(e.OverallProgressPercentage * 100);
264
265            long amountToDownload = 0;
266            foreach (ListViewItem lvItem in downloadingLv.Items)
267                try
268                {
269                    amountToDownload +=
270                        Convert.ToInt32(lvItem.SubItems[1].Text);
271                }
272                catch (FormatException)
273                {
274                }
275
276            downloadingOverallLbl.Text = string.Format(S._("Overall progress: {0} bytes left"),
277                amountToDownload);
278        }
279
280        /// <summary>
281        /// Handles the completion of updating event
282        /// </summary>
283        /// <param name="sender">The object triggering this event/</param>
284        /// <param name="e">Event argument.</param>
285        private void downloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
286        {
287            if (e.Error != null)
288            {
289                MessageBox.Show(this, e.Error.Message, S._("Eraser"), MessageBoxButtons.OK,
290                    MessageBoxIcon.Error);
291                Close();
292                return;
293            }
294
295            downloadingPnl.Visible = false;
296            installingPnl.Show();
297
298            foreach (ListViewItem item in downloadingLv.Items)
299            {
300                item.Remove();
301                installingLv.Items.Add(item);
302
303                UpdateData update = uiUpdates[(UpdateManager.Update)item.Tag];
304                if (update.Error == null)
305                    item.SubItems[1].Text = string.Empty;
306                else
307                    item.SubItems[1].Text = string.Format(S._("Error: {0}"),
308                        update.Error.Message);
309            }
310
311            installer.RunWorkerAsync(e.Result);
312        }
313        #endregion
314
315        #region Update installer
316        /// <summary>
317        /// Background thread to install downloaded updates
318        /// </summary>
319        /// <param name="sender">The object triggering this event/</param>
320        /// <param name="e">Event argument.</param>
321        private void installer_DoWork(object sender, DoWorkEventArgs e)
322        {
323            try
324            {
325                updates.OnProgressEvent += installer_ProgressChanged;
326                updates.InstallUpdates(e.Argument);
327            }
328            finally
329            {
330                updates.OnProgressEvent -= installer_ProgressChanged;
331            }
332        }
333
334        /// <summary>
335        /// Handles the progress events generated during update installation.
336        /// </summary>
337        /// <param name="sender">The object triggering this event/</param>
338        /// <param name="e">Event argument.</param>
339        private void installer_ProgressChanged(object sender, ProgressChangedEventArgs e)
340        {
341            if (InvokeRequired)
342            {
343                Invoke(new UpdateManager.ProgressEventFunction(installer_ProgressChanged),
344                    sender, e);
345                return;
346            }
347
348            UpdateData update = uiUpdates[(UpdateManager.Update)e.UserState];
349            if (e is UpdateManager.ProgressErrorEventArgs)
350            {
351                update.Error = ((UpdateManager.ProgressErrorEventArgs)e).Exception;
352                update.LVItem.ImageIndex = 3;
353                update.LVItem.SubItems[1].Text = string.Format(S._("Error: {0}"),
354                    update.Error.Message);
355            }
356            else
357                switch (update.LVItem.ImageIndex)
358                {
359                    case -1:
360                        update.LVItem.ImageIndex = 1;
361                        break;
362                    case 1:
363                        update.LVItem.ImageIndex = 2;
364                        break;
365                }
366        }
367        #endregion
368
369        /// <summary>
370        /// The Update manager instance used by this form.
371        /// </summary>
372        UpdateManager updates;
373
374        /// <summary>
375        /// Maps listview items to the UpdateManager.Update object.
376        /// </summary>
377        Dictionary<UpdateManager.Update, UpdateData> uiUpdates =
378            new Dictionary<UpdateManager.Update, UpdateData>();
379
380        /// <summary>
381        /// Manages information associated with the update.
382        /// </summary>
383        private class UpdateData
384        {
385            /// <summary>
386            /// Constructor.
387            /// </summary>
388            /// <param name="update">The UpdateManager.Update object containing the
389            /// internal representation of the update.</param>
390            /// <param name="item">The ListViewItem used for the display of the
391            /// update.</param>
392            public UpdateData(UpdateManager.Update update, ListViewItem item)
393            {
394                Update = update;
395                LVItem = item;
396                Error = null;
397            }
398
399            /// <summary>
400            /// The UpdateManager.Update object containing the internal representation
401            /// of the update.
402            /// </summary>
403            public UpdateManager.Update Update;
404
405            /// <summary>
406            /// The ListViewItem used for the display of the update.
407            /// </summary>
408            public ListViewItem LVItem;
409
410            /// <summary>
411            /// The error raised when downloading/installing the update, if any. Null
412            /// otherwise.
413            /// </summary>
414            public Exception Error;
415        }
416    }
417
418    public class UpdateManager
419    {
420        /// <summary>
421        /// Represents an update available on the server.
422        /// </summary>
423        public struct Update
424        {
425            public string Name;
426            public Version Version;
427            public string Publisher;
428            public string Architecture;
429            public long FileSize;
430            public string Link;
431        }
432
433        /// <summary>
434        /// Specialised progress event argument, containing message describing
435        /// current action, and overall progress percentage.
436        /// </summary>
437        public class ProgressEventArgs : ProgressChangedEventArgs
438        {
439            public ProgressEventArgs(float progressPercentage, float overallPercentage,
440                object userState, string message)
441                : base((int)(progressPercentage * 100), userState)
442            {
443                this.progressPercentage = progressPercentage;
444                this.overallProgressPercentage = overallPercentage;
445                this.message = message;
446            }
447
448            /// <summary>
449            /// Gets the asynchronous task progress percentage.
450            /// </summary>
451            public new float ProgressPercentage
452            {
453                get
454                {
455                    return progressPercentage;
456                }
457            }
458
459            /// <summary>
460            /// Gets the asynchronous task overall progress percentage.
461            /// </summary>
462            public float OverallProgressPercentage
463            {
464                get
465                {
466                    return overallProgressPercentage;
467                }
468            }
469
470            /// <summary>
471            /// Gets the message associated with the current task.
472            /// </summary>
473            public string Message
474            {
475                get
476                {
477                    return message;
478                }
479            }
480
481            float progressPercentage;
482            float overallProgressPercentage;
483            string message;
484        }
485
486        /// <summary>
487        /// Extends the ProgressEventArgs further by allowing for the inclusion of
488        /// an exception.
489        /// </summary>
490        public class ProgressErrorEventArgs : ProgressEventArgs
491        {
492            /// <summary>
493            /// Constructor.
494            /// </summary>
495            /// <param name="e">The base ProgressEventArgs object.</param>
496            /// <param name="ex">The exception</param>
497            public ProgressErrorEventArgs(ProgressEventArgs e, Exception ex)
498                : base(e.ProgressPercentage, e.OverallProgressPercentage, e.UserState, e.Message)
499            {
500                this.exception = ex;
501            }
502
503            /// <summary>
504            /// The exception associated with the progress event.
505            /// </summary>
506            public Exception Exception
507            {
508                get
509                {
510                    return exception;
511                }
512            }
513
514            private Exception exception;
515        }
516
517        /// <summary>
518        /// Retrieves the update list from the server.
519        /// </summary>
520        public void GetUpdates()
521        {
522            WebRequest.DefaultCachePolicy = new HttpRequestCachePolicy(
523                HttpRequestCacheLevel.Refresh);
524            HttpWebRequest req = (HttpWebRequest)
525                WebRequest.Create("http://eraser.sourceforge.net/updates?action=listupdates&" +
526                    "version=" + Assembly.GetExecutingAssembly().GetName().Version.ToString());
527           
528            using (WebResponse resp = req.GetResponse())
529            using (Stream strm = resp.GetResponseStream())
530            {
531                //Download the response
532                int bytesRead = 0;
533                byte[] buffer = new byte[16384];
534                List<byte> responseBuffer = new List<byte>();
535                while ((bytesRead = strm.Read(buffer, 0, buffer.Length)) != 0)
536                {
537                    byte[] tmpDest = new byte[bytesRead];
538                    Buffer.BlockCopy(buffer, 0, tmpDest, 0, bytesRead);
539                    responseBuffer.AddRange(tmpDest);
540
541                    float progress = responseBuffer.Count / (float)resp.ContentLength;
542                    OnProgress(new ProgressEventArgs(progress, progress, null,
543                        string.Format(S._("{0} of {1} bytes downloaded"),
544                            responseBuffer.Count, resp.ContentLength)));
545                }
546
547                //Parse it.
548                using (MemoryStream mStrm = new MemoryStream(responseBuffer.ToArray()))
549                    ParseUpdateList(mStrm);
550            }
551        }
552
553        /// <summary>
554        /// Parses the list of updates provided by the server
555        /// </summary>
556        /// <param name="strm">The stream containing the XML data.</param>
557        private void ParseUpdateList(Stream strm)
558        {
559            //Move the XmlReader to the root node
560            updates.Clear();
561            mirrors.Clear();
562            XmlReader rdr = XmlReader.Create(strm);
563            rdr.ReadToFollowing("updateList");
564
565            //Read the descendants of the updateList node (which are categories,
566            //except for the <mirrors> element)
567            XmlReader categories = rdr.ReadSubtree();
568            bool cont = categories.ReadToDescendant("updates");
569            while (cont)
570            {
571                if (categories.NodeType == XmlNodeType.Element)
572                {
573                    if (categories.Name == "mirrors")
574                    {
575                        Dictionary<string, string> mirrorsList =
576                            ParseMirror(categories.ReadSubtree());
577                        Dictionary<string, string>.Enumerator e = mirrorsList.GetEnumerator();
578                        while (e.MoveNext())
579                            this.mirrors.Add(e.Current.Key, e.Current.Value);
580                    }
581                    else
582                        updates.Add(categories.Name, ParseUpdateCategory(categories.ReadSubtree()));
583                }
584
585                cont = categories.Read();
586            }
587        }
588
589        /// <summary>
590        /// Parses a list of mirrors.
591        /// </summary>
592        /// <param name="rdr">The XML reader object representing the &lt;mirrors&gt; node</param>
593        /// <returns>The list of mirrors defined by the element.</returns>
594        private static Dictionary<string, string> ParseMirror(XmlReader rdr)
595        {
596            Dictionary<string, string> result = new Dictionary<string,string>();
597            if (!rdr.ReadToDescendant("mirror"))
598                return result;
599
600            //Load every element.
601            do
602            {
603                if (rdr.Name != "mirror")
604                    continue;
605
606                result.Add(rdr.ReadElementContentAsString(), rdr.GetAttribute("location"));
607            }
608            while (rdr.ReadToNextSibling("mirror"));
609
610            return result;
611        }
612
613        /// <summary>
614        /// Parses a specific category and its assocaited updates.
615        /// </summary>
616        /// <param name="rdr">The XML reader object representing the element and its children.</param>
617        /// <returns>A list of updates in the category.</returns>
618        private static List<Update> ParseUpdateCategory(XmlReader rdr)
619        {
620            List<Update> result = new List<Update>();
621            if (!rdr.ReadToDescendant("item"))
622                return result;
623
624            //Load every element.
625            do
626            {
627                if (rdr.Name != "item")
628                    continue;
629
630                Update update = new Update();
631                update.Name = rdr.GetAttribute("name");
632                update.Version = new Version(rdr.GetAttribute("version"));
633                update.Publisher = rdr.GetAttribute("publisher");
634                update.Architecture = rdr.GetAttribute("architecture");
635                update.FileSize = Convert.ToInt64(rdr.GetAttribute("filesize"));
636                update.Link = rdr.ReadElementContentAsString();
637
638                result.Add(update);
639            }
640            while (rdr.ReadToNextSibling("item"));
641
642            return result;
643        }
644
645        /// <summary>
646        /// Downloads the list of updates.
647        /// </summary>
648        /// <param name="updates">The updates to retrieve and install.</param>
649        /// <returns>An opaque object for use with InstallUpdates.</returns>
650        public object DownloadUpdates(List<Update> updates)
651        {
652            string mirror = "http://eraser.sourceforge.net";
653            //Create a folder to hold all our updates.
654            DirectoryInfo tempDir = new DirectoryInfo(Path.GetTempPath());
655            tempDir = tempDir.CreateSubdirectory("eraser" + Environment.TickCount.ToString());
656
657            int currUpdate = 0;
658            Dictionary<string, Update> tempFilesMap = new Dictionary<string, Update>();
659            foreach (Update update in updates)
660            {
661                try
662                {
663                    //Decide on the URL to connect to. The Link of the update may
664                    //be a relative path (relative to the selected mirror) or an
665                    //absolute path (which we have no choice)
666                    Uri reqUri = new Uri(update.Link);
667                    if (!reqUri.IsAbsoluteUri)
668                        reqUri = new Uri(new Uri(mirror), update.Link);
669
670                    //Then grab the download.
671                    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(reqUri);
672                    using (WebResponse resp = req.GetResponse())
673                    {
674                        byte[] tempBuffer = new byte[16384];
675                        string tempFilePath = Path.Combine(
676                            tempDir.FullName, string.Format("{0}-{1}", ++currUpdate,
677                            Path.GetFileName(reqUri.GetComponents(UriComponents.Path, UriFormat.Unescaped))));
678
679                        using (Stream strm = resp.GetResponseStream())
680                        using (FileStream tempStrm = new FileStream(tempFilePath, FileMode.CreateNew))
681                        using (BufferedStream bufStrm = new BufferedStream(tempStrm))
682                        {
683                            //Copy the information into the file stream
684                            int readBytes = 0;
685                            while ((readBytes = strm.Read(tempBuffer, 0, tempBuffer.Length)) != 0)
686                            {
687                                bufStrm.Write(tempBuffer, 0, readBytes);
688
689                                //Compute progress
690                                float itemProgress = tempStrm.Position / (float)resp.ContentLength;
691                                float overallProgress = (currUpdate - 1 + itemProgress) / updates.Count;
692                                OnProgress(new ProgressEventArgs(itemProgress, overallProgress,
693                                    update, string.Format(S._("Downloading: {0}"), update.Name)));
694                            }
695                        }
696
697                        //Store the filename-to-update mapping
698                        tempFilesMap.Add(tempFilePath, update);
699
700                        //Let the event handler know the download is complete.
701                        OnProgress(new ProgressEventArgs(1.0f, currUpdate - 1,
702                            update, string.Format(S._("Downloaded: {0}"), update.Name)));
703                    }
704                }
705                catch (Exception e)
706                {
707                    OnProgress(new ProgressErrorEventArgs(new ProgressEventArgs(1.0f,
708                        (float)currUpdate / updates.Count, update,
709                            string.Format(S._("Error downloading {0}: {1}"), update.Name, e.Message)),
710                        e));
711                }
712            }
713
714            return tempFilesMap;
715        }
716
717        public void InstallUpdates(object downloadObject)
718        {
719            Dictionary<string, Update> tempFiles = (Dictionary<string, Update>)downloadObject;
720            Dictionary<string, Update>.KeyCollection files = tempFiles.Keys;
721            int currItem = 0;
722
723            try
724            {
725                foreach (string path in files)
726                {
727                    Update item = tempFiles[path];
728                    float progress = (float)currItem++ / files.Count;
729                    OnProgress(new ProgressEventArgs(0.0f, progress,
730                        item, string.Format(S._("Installing {0}"), item.Name)));
731
732                    System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo();
733                    info.FileName = path;
734                    info.UseShellExecute = true;
735
736                    System.Diagnostics.Process process = System.Diagnostics.Process.Start(info);
737                    process.WaitForExit(Int32.MaxValue);
738                    if (process.ExitCode == 0)
739                        OnProgress(new ProgressEventArgs(1.0f, progress,
740                            item, string.Format(S._("Installed {0}"), item.Name)));
741                    else
742                        OnProgress(new ProgressErrorEventArgs(new ProgressEventArgs(1.0f,
743                            progress, item, string.Format(S._("Error installing {0}"), item.Name)),
744                            new Exception(string.Format(S._("The installer exited with an error code {0}"),
745                                process.ExitCode))));
746                }
747            }
748            finally
749            {
750                //Clean up after ourselves
751                foreach (string file in files)
752                {
753                    DirectoryInfo tempDir = null;
754                    {
755                        FileInfo info = new FileInfo(file);
756                        tempDir = info.Directory;
757                    }
758
759                    tempDir.Delete(true);
760                }
761            }
762        }
763
764        /// <summary>
765        /// Prototype of the callback functions from this object.
766        /// </summary>
767        /// <param name="sender">The source of the event.</param>
768        /// <param name="arg">The ProgressEventArgs object holding information
769        /// about the progress of the current operation.</param>
770        public delegate void ProgressEventFunction(object sender, ProgressEventArgs arg);
771
772        /// <summary>
773        /// Called when the progress of the operation changes.
774        /// </summary>
775        public ProgressEventFunction OnProgressEvent;
776
777        /// <summary>
778        /// Helper function: invokes the OnProgressEvent delegate.
779        /// </summary>
780        /// <param name="arg">The ProgressEventArgs object holding information
781        /// about the progress of the current operation.</param>
782        private void OnProgress(ProgressEventArgs arg)
783        {
784            if (OnProgressEvent != null)
785                OnProgressEvent(this, arg);
786        }
787
788        /// <summary>
789        /// Retrieves the categories available.
790        /// </summary>
791        public Dictionary<string, List<Update>>.KeyCollection Categories
792        {
793            get
794            {
795                return updates.Keys;
796            }
797        }
798
799        /// <summary>
800        /// Retrieves all updates available.
801        /// </summary>
802        public Dictionary<string, List<Update>> Updates
803        {
804            get
805            {
806                return updates;
807            }
808        }
809
810        /// <summary>
811        /// Retrieves the updates in the given category.
812        /// </summary>
813        /// <param name="key">The category to retrieve.</param>
814        /// <returns>All updates in the given category.</returns>
815        public List<Update> this[string key]
816        {
817            get
818            {
819                return updates[key];
820            }
821        }
822
823        /// <summary>
824        /// The list of mirrors to download updates from.
825        /// </summary>
826        private Dictionary<string, string> mirrors = new Dictionary<string, string>();
827
828        /// <summary>
829        /// The list of updates downloaded.
830        /// </summary>
831        private Dictionary<string, List<Update>> updates =
832            new Dictionary<string, List<Update>>();
833    }
834}
Note: See TracBrowser for help on using the repository browser.