예제 #1
0
        protected virtual IUpdateTask CreateUpdateTask(EntityDto entity)
        {
            IUpdateTask task = this.GetNewUpdateTaskInstance();

            task.EntityToUpdate = entity;
            return(task);
        }
예제 #2
0
        public void TestTasks2()
        {
            TasksRunner tasksRunner = new TasksRunner(this.WSAccessKey, this.FileUid);
            IInsertTask insertTask  = null;
            IUpdateTask updateTask  = null;

            this.MrsSmith.PostalAddress.Street = "11/111 ABC Av";
            this.MrsSmith.PostalAddress.City   = "Sydney";
            this.MrsSmith.PostalAddress.State  = "NSW";
            this.MrsSmith.MobilePhone          = "0666 666 666";

            updateTask = new UpdateContactTask();
            updateTask.EntityToUpdate = this.MrsSmith;
            tasksRunner.Tasks.Add(updateTask);

            SaleTests saleTests = new SaleTests();

            saleTests.TestFixtureSetUp();

            insertTask = new InsertInvoiceTask();
            InvoiceDto invoiceDto = saleTests.GetServiceSale();

            invoiceDto.ContactUid     = 99999;
            insertTask.EntityToInsert = invoiceDto;
            tasksRunner.Tasks.Add(insertTask);

            insertTask = new InsertInvoiceTask();
            insertTask.EntityToInsert = saleTests.GetUnpaidItemSale();
            tasksRunner.Tasks.Add(insertTask);

            TasksResponse response = tasksRunner.Execute();
        }
예제 #3
0
        public bool IsMet(IUpdateTask task)
        {
            var localPath = !string.IsNullOrEmpty(LocalPath)
                                ? LocalPath
                                : Utils.Reflection.GetNauAttribute(task, "LocalPath") as string;

            // local path is invalid, we can't check for anything so we will return as if the condition was met
            if (string.IsNullOrEmpty(localPath))
            {
                return(true);
            }

            // if the local file does not exist, checksums don't match vacuously
            if (!File.Exists(localPath))
            {
                return(false);
            }

            if ("sha256".Equals(ChecksumType, StringComparison.InvariantCultureIgnoreCase))
            {
                var sha256 = FileChecksum.GetSHA256Checksum(localPath);
                if (!string.IsNullOrEmpty(sha256) && sha256.Equals(Checksum, StringComparison.InvariantCultureIgnoreCase))
                {
                    return(true);
                }
            }

            // TODO: Support more checksum algorithms (although SHA256 isn't known to have collisions, other are more commonly used)

            return(false);
        }
예제 #4
0
        public void PrepareTest()
        {
            var ws = new WebSource();
            _ft = new AppcastReader().Read(ws.GetUpdatesFeed(FeedUrl));
            _ft.Prepare(ws);

            Assert.IsTrue(File.Exists(_ft.PathToZippedUpdate));
        }
예제 #5
0
 public void Init(IUpdateTask currentUpdate)
 {
     // lblDate.Text = currentUpdate.
     lblVersion.Text = currentUpdate.FileVersion.ToString();
     lblTaille.Text = ConvertByteToMegaByte(currentUpdate.FileLength.ToString());
     txtSignature.Text = currentUpdate.Checksum;
     txtDescription.Text = currentUpdate.Description;
     txtDescription.ReadOnly = true;
 }
        public bool IsMet(IUpdateTask task)
        {
            if (!Attributes.ContainsKey("version"))
                return false;
 
            var localVersion = new Version(_applicationVersion);
            var updateVersion = new Version(Attributes["version"]);
             
            return updateVersion > localVersion;
        }
예제 #7
0
        internal static void RemoveEditorUpdateTask(IUpdateTask job)
        {
            //Check if the job hasn't been actually added yet
            if (m_requestedTasks.Contains(job))
            {
                m_requestedTasks.Remove(job);
                return;
            }

            Assert.IsTrue(m_mainThreadPeriodJobs.Contains(job));
            m_toRemoveTasks.Add(job);
        }
        public bool IsMet(IUpdateTask task)
        {
            var localPath = !string.IsNullOrEmpty(LocalPath)
                                ? LocalPath
                                : Reflection.GetNauAttribute(task, "LocalPath") as string;

            if (string.IsNullOrEmpty(localPath))
            {
                return(true);
            }
            var fullPath = FileSystem.GetFullPath(localPath);

            return(File.Exists(fullPath));
        }
예제 #9
0
        public bool IsMet(IUpdateTask task)
        {
            if (Timestamp == DateTime.MinValue)
            {
                return(true);
            }

            var localPath = !string.IsNullOrEmpty(LocalPath)
                                ? LocalPath
                                : Reflection.GetNauAttribute(task, "LocalPath") as string;

            // local path is invalid, we can't check for anything so we will return as if the condition was met
            if (string.IsNullOrEmpty(localPath))
            {
                return(true);
            }

            var fullPath = FileSystem.GetFullPath(localPath);

            // if the file doesn't exist it has a null timestamp, and therefore the condition result depends on the ComparisonType
            if (!File.Exists(fullPath))
            {
                return(ComparisonType.Equals("older", StringComparison.InvariantCultureIgnoreCase));
            }

            // File timestamps seem to be off by a little bit (conversion rounding?), so the code below
            // gets around that
            var dt                 = File.GetLastWriteTime(fullPath);
            var localPlus          = dt.AddSeconds(2).ToFileTimeUtc();
            var localMinus         = dt.AddSeconds(-2).ToFileTimeUtc();
            var remoteFileDateTime = Timestamp.ToFileTimeUtc();

            bool result;

            switch (ComparisonType)
            {
            case "newer":
                result = localMinus > remoteFileDateTime;
                break;

            case "is":
                result = localMinus <= remoteFileDateTime && remoteFileDateTime <= localPlus;
                break;

            default:
                result = localPlus < remoteFileDateTime;
                break;
            }
            return(result);
        }
예제 #10
0
 public TaskController(IRetrieveTask retrieveTask,
                       ICreateTask createTask,
                       IUpdateTask updateTask,
                       IDeleteTask deleteTask,
                       IDeleteBulk deleteBulk,
                       IMoveTask moveTask,
                       ITaskStatus taskStatus)
 {
     _retrieveTask = retrieveTask;
     _createTask   = createTask;
     _updateTask   = updateTask;
     _deleteTask   = deleteTask;
     _deleteBulk   = deleteBulk;
     _moveTask     = moveTask;
     _taskStatus   = taskStatus;
 }
예제 #11
0
        public bool IsMet(IUpdateTask task)
        {
            string localPath = !string.IsNullOrEmpty(LocalPath) ? LocalPath : Utils.Reflection.GetNauAttribute(task, "LocalPath") as string;
            if (string.IsNullOrEmpty(localPath) || !File.Exists(localPath))
                return true;

            if ("sha256".Equals(ChecksumType, StringComparison.InvariantCultureIgnoreCase))
            {
                string sha256 = Utils.FileChecksum.GetSHA256Checksum(localPath);
                if (!string.IsNullOrEmpty(sha256) && sha256.Equals(Checksum))
                    return true;
            }

            // TODO: Support more checksum algorithms (although SHA256 isn't known to have collisions, other are more commonly used)

            return false;
        }
예제 #12
0
        private void TaskProgressCallback(UpdateProgressInfo currentStatus, IUpdateTask task)
        {
            if (ReportProgress == null)
            {
                return;
            }

            currentStatus.TaskDescription = task.Description;
            currentStatus.TaskId          = UpdatesToApply.IndexOf(task) + 1;

            //This was an assumed int, which meant we never reached 100% with an odd number of tasks
            float taskPerc = 100F / UpdatesToApply.Count;

            currentStatus.Percentage = (int)Math.Round((currentStatus.Percentage * taskPerc / 100) + (currentStatus.TaskId - 1) * taskPerc);

            ReportProgress(currentStatus);
        }
예제 #13
0
        public bool IsMet(IUpdateTask task)
        {
            if (ChildConditions == null)
            {
                return(true);
            }

            // perform the update if Passed == true
            // otherwise, do not perform the update
            bool passed = true, firstRun = true;

            foreach (var item in ChildConditions)
            {
                // If after the first iteration, accept as fulfilled if we are at an OR clause and the conditions
                // before this checked OK (i.e. update needed)
                if (!firstRun)
                {
                    if (passed && item.HasConditionType(ConditionType.OR))
                    {
                        return(true);
                    }
                }
                else
                {
                    firstRun = false;
                }

                // Skip all ANDed conditions if some of them failed, until we consume all the conditions
                // or we hit an OR'ed one
                if (!passed)
                {
                    if (item.HasConditionType(ConditionType.OR))
                    {
                        var checkResult = item._Condition.IsMet(task);
                        passed = item.HasConditionType(ConditionType.NOT) ? !checkResult : checkResult;
                    }
                }
                else
                {
                    var checkResult = item._Condition.IsMet(task);
                    passed = item.HasConditionType(ConditionType.NOT) ? !checkResult : checkResult;
                }
            }

            return(passed);
        }
예제 #14
0
        public bool IsMet(IUpdateTask task)
        {
            var localPath = !string.IsNullOrEmpty(LocalPath)
                                ? LocalPath
                                : Reflection.GetNauAttribute(task, "LocalPath") as string;

            // local path is invalid, we can't check for anything so we will return as if the condition was met
            if (string.IsNullOrEmpty(localPath))
            {
                return(true);
            }

            var fullPath = FileSystem.GetFullPath(localPath);

            // if the file doesn't exist it has a null version, and therefore the condition result depends on the ComparisonType
            if (!File.Exists(fullPath))
            {
                return(ComparisonType.Equals("below", StringComparison.InvariantCultureIgnoreCase));
            }

            var versionInfo = FileVersionInfo.GetVersionInfo(fullPath);

            if (versionInfo.FileVersion == null)
            {
                return(true);                                             // perform the update if no version info is found
            }
            var localVersion = new Version(versionInfo.FileMajorPart, versionInfo.FileMinorPart, versionInfo.FileBuildPart,
                                           versionInfo.FilePrivatePart);
            var updateVersion = Version != null ? new Version(Version) : new Version();

            switch (ComparisonType)
            {
            case "above":
                return(updateVersion < localVersion);

            case "is":
                return(updateVersion == localVersion);

            default:
                return(updateVersion > localVersion);
            }
        }
예제 #15
0
        // TODO: Work with enums on code and Attributes to get a proper and full OS version comparison
        // use http://stackoverflow.com/questions/545666/how-to-translate-ms-windows-os-version-numbers-into-product-names-in-net
        // and http://msdn.microsoft.com/en-us/library/ms724429(VS.85).aspx

        public bool IsMet(IUpdateTask task)
        {
            var is64Bit = Is64BitOperatingSystem();

            if (OsBits == 32 && OsBits != 64)
            {
                return(true);
            }

            // OS bitness check, if requested
            if (OsBits == 32 && is64Bit)
            {
                return(false);
            }
            if (OsBits == 64 && !is64Bit)
            {
                return(false);
            }

            return(true);
        }
        public bool IsMet(IUpdateTask task)
        {
            string localPath = !string.IsNullOrEmpty(LocalPath) ? LocalPath : Utils.Reflection.GetNauAttribute(task, "LocalPath") as string;

            if (string.IsNullOrEmpty(localPath) || !File.Exists(localPath))
            {
                return(true);
            }

            if ("sha256".Equals(ChecksumType, StringComparison.InvariantCultureIgnoreCase))
            {
                string sha256 = Utils.FileChecksum.GetSHA256Checksum(localPath);
                if (!string.IsNullOrEmpty(sha256) && sha256.Equals(Checksum.ToUpper()))
                {
                    return(true);
                }
            }

            // TODO: Support more checksum algorithms (although SHA256 isn't known to have collisions, other are more commonly used)

            return(false);
        }
예제 #17
0
        public bool IsMet(IUpdateTask task)
        {
            var localPath = !string.IsNullOrEmpty(LocalPath) ? LocalPath : Utils.Reflection.GetNauAttribute(task, "LocalPath") as string;

            // local path is invalid, we can't check for anything so we will return as if the condition was met
            if (string.IsNullOrEmpty(localPath))
                return true;

            // if the local file does not exist, checksums don't match vacuously
            if (!File.Exists(localPath))
                return false;

            if ("sha256".Equals(ChecksumType, StringComparison.InvariantCultureIgnoreCase))
            {
                var sha256 = Utils.FileChecksum.GetSHA256Checksum(localPath);
                if (!string.IsNullOrEmpty(sha256) && sha256.Equals(Checksum, StringComparison.InvariantCultureIgnoreCase))
                    return true;
            }

            // TODO: Support more checksum algorithms (although SHA256 isn't known to have collisions, other are more commonly used)

            return false;
        }
예제 #18
0
        public bool IsMet(IUpdateTask task)
        {
            if (FileSize <= 0)
            {
                return(true);
            }

            var localPath = !string.IsNullOrEmpty(LocalPath)
                                ? LocalPath
                                : Reflection.GetNauAttribute(task, "LocalPath") as string;

            // local path is invalid, we can't check for anything so we will return as if the condition was met
            if (string.IsNullOrEmpty(localPath))
            {
                return(true);
            }

            var fullPath = FileSystem.GetFullPath(localPath);

            long localFileSize = 0;

            if (File.Exists(fullPath))
            {
                var fi = new FileInfo(fullPath);
                localFileSize = fi.Length;
            }

            switch (ComparisonType)
            {
            case "above":
                return(FileSize < localFileSize);

            case "is":
                return(FileSize == localFileSize);
            }
            return(FileSize > localFileSize);
        }
예제 #19
0
		private void TaskProgressCallback(UpdateProgressInfo currentStatus, IUpdateTask task)
		{
			if (ReportProgress == null) return;

			currentStatus.TaskDescription = task.Description;
			currentStatus.TaskId = UpdatesToApply.IndexOf(task) + 1;

			//This was an assumed int, which meant we never reached 100% with an odd number of tasks
			float taskPerc = 100F / UpdatesToApply.Count;
			currentStatus.Percentage = (int)Math.Round((currentStatus.Percentage * taskPerc / 100) + (currentStatus.TaskId - 1) * taskPerc);

			ReportProgress(currentStatus);
		}
예제 #20
0
        public bool IsMet(IUpdateTask task)
        {
            var desired = new Version(Attributes["version"]);

            return desired > _current;
        }
예제 #21
0
        public bool IsMet(IUpdateTask task)
        {
            var desired = new Version(Attributes["version"]);

            return(desired > _current);
        }
예제 #22
0
        private void TaskProgressCallback(UpdateProgressInfo currentStatus, IUpdateTask task)
        {
            if (ReportProgress == null) return;

            currentStatus.TaskDescription = task.Description;
            currentStatus.TaskId = UpdatesToApply.IndexOf(task) + 1;

            var taskPerc = 100 / UpdatesToApply.Count;
            currentStatus.Percentage = (currentStatus.Percentage * taskPerc / 100) + (currentStatus.TaskId - 1) * taskPerc;

            ReportProgress(currentStatus);
        }
예제 #23
0
 public bool IsMet(IUpdateTask task)
 {
     return(_isMet);
 }
예제 #24
0
        /// <summary>
        /// Starts the updater executable and sends update data to it
        /// </summary>
        /// <param name="relaunchApplication">true if relaunching the caller application is required; false otherwise</param>
        /// <param name="updaterDoLogging">true if the updater writes to a log file; false otherwise</param>
        /// <param name="updaterShowConsole">true if the updater shows the console window; false otherwise</param>
        /// <returns>True if successful (unless a restart was required</returns>
        public void ApplyUpdates(bool relaunchApplication, bool updaterDoLogging, bool updaterShowConsole)
        {
            if (IsWorking)
            {
                throw new InvalidOperationException("Another update process is already in progress");
            }

            lock (UpdatesToApply)
            {
                using (WorkScope.New(isWorking => IsWorking = isWorking))
                {
                    bool revertToDefaultBackupPath = true;

                    // Set current directory the the application directory
                    // this prevents the updater from writing to e.g. c:\windows\system32
                    // if the process is started by autorun on windows logon.
                    // ReSharper disable AssignNullToNotNullAttribute
                    Environment.CurrentDirectory = Path.GetDirectoryName(ApplicationPath);
                    // ReSharper restore AssignNullToNotNullAttribute

                    // Make sure the current backup folder is accessible for writing from this process
                    string backupParentPath = Path.GetDirectoryName(Config.BackupFolder) ?? string.Empty;
                    if (Directory.Exists(backupParentPath) && PermissionsCheck.HaveWritePermissionsForFolder(backupParentPath))
                    {
                        // Remove old backup folder, in case this same folder was used previously,
                        // and it wasn't removed for some reason
                        try
                        {
                            if (Directory.Exists(Config.BackupFolder))
                            {
                                FileSystem.DeleteDirectory(Config.BackupFolder);
                            }
                            revertToDefaultBackupPath = false;
                        }
                        catch (UnauthorizedAccessException)
                        {
                        }

                        // Attempt to (re-)create the backup folder
                        try
                        {
                            Directory.CreateDirectory(Config.BackupFolder);

                            if (!PermissionsCheck.HaveWritePermissionsForFolder(Config.BackupFolder))
                            {
                                revertToDefaultBackupPath = true;
                            }
                        }
                        catch (UnauthorizedAccessException)
                        {
                            // We're having permissions issues with this folder, so we'll attempt
                            // using a backup in a default location
                            revertToDefaultBackupPath = true;
                        }
                    }

                    if (revertToDefaultBackupPath)
                    {
                        Config._backupFolder = Path.Combine(
                            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                            Config.UpdateProcessName + "UpdateBackups" + DateTime.UtcNow.Ticks);

                        try
                        {
                            Directory.CreateDirectory(Config.BackupFolder);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            // We can't backup, so we abort
                            throw new UpdateProcessFailedException("Could not create backup folder " + Config.BackupFolder, ex);
                        }
                    }

                    bool runPrivileged = false, hasColdUpdates = false;
                    State = UpdateProcessState.RollbackRequired;
                    foreach (var task in UpdatesToApply)
                    {
                        IUpdateTask t = task;
                        task.ProgressDelegate += status => TaskProgressCallback(status, t);

                        try
                        {
                            // Execute the task
                            task.ExecutionStatus = task.Execute(false);
                        }
                        catch (Exception ex)
                        {
                            task.ExecutionStatus = TaskExecutionStatus.Failed;                             // mark the failing task before rethrowing
                            throw new UpdateProcessFailedException("Update task execution failed: " + task.Description, ex);
                        }

                        if (task.ExecutionStatus == TaskExecutionStatus.RequiresAppRestart ||
                            task.ExecutionStatus == TaskExecutionStatus.RequiresPrivilegedAppRestart)
                        {
                            // Record that we have cold updates to run, and if required to run any of them privileged
                            runPrivileged  = runPrivileged || task.ExecutionStatus == TaskExecutionStatus.RequiresPrivilegedAppRestart;
                            hasColdUpdates = true;
                            continue;
                        }

                        // We are being quite explicit here - only Successful return values are considered
                        // to be Ok (cold updates are already handled above)
                        if (task.ExecutionStatus != TaskExecutionStatus.Successful)
                        {
                            throw new UpdateProcessFailedException("Update task execution failed: " + task.Description);
                        }
                    }

                    // If an application restart is required
                    if (hasColdUpdates)
                    {
                        var dto = new NauIpc.NauDto
                        {
                            Configs             = Instance.Config,
                            Tasks               = Instance.UpdatesToApply,
                            AppPath             = ApplicationPath,
                            WorkingDirectory    = Environment.CurrentDirectory,
                            RelaunchApplication = relaunchApplication,
                            LogItems            = Logger.LogItems,
                        };

                        NauIpc.ExtractUpdaterFromResource(Config.TempFolder, Instance.Config.UpdateExecutableName);

                        var info = new ProcessStartInfo
                        {
                            UseShellExecute  = true,
                            WorkingDirectory = Environment.CurrentDirectory,
                            FileName         = Path.Combine(Config.TempFolder, Instance.Config.UpdateExecutableName),
                            Arguments        =
                                string.Format(@"""{0}"" {1} {2}", Config.UpdateProcessName,
                                              updaterShowConsole ? "-showConsole" : string.Empty,
                                              updaterDoLogging ? "-log" : string.Empty),
                        };

                        if (!updaterShowConsole)
                        {
                            info.WindowStyle    = ProcessWindowStyle.Hidden;
                            info.CreateNoWindow = true;
                        }

                        // If we can't write to the destination folder, then lets try elevating priviledges.
                        if (runPrivileged || !PermissionsCheck.HaveWritePermissionsForFolder(Environment.CurrentDirectory))
                        {
                            info.Verb = "runas";
                        }

                        bool createdNew;
                        _shutdownMutex = new Mutex(true, Config.UpdateProcessName + "Mutex", out createdNew);

                        try
                        {
                            NauIpc.LaunchProcessAndSendDto(dto, info, Config.UpdateProcessName);
                        }
                        catch (Exception ex)
                        {
                            throw new UpdateProcessFailedException("Could not launch cold update process", ex);
                        }

                        Environment.Exit(0);
                    }

                    State = UpdateProcessState.AppliedSuccessfully;
                    UpdatesToApply.Clear();
                }
            }
        }
예제 #25
0
 public void EnqueueTask(IUpdateTask task)
 {
     Tasks.Enqueue(task);
     ResetEvent.Set();
 }
예제 #26
0
//----------------------------------------------------------------------------------------------------------------------

        internal static void AddEditorUpdateTask(IUpdateTask job)
        {
            m_requestedTasks.Add(job);
        }
예제 #27
0
        public IList <IUpdateTask> Read(string feed)
        {
            // Lazy-load the Condition and Task objects contained in this assembly, unless some have already
            // been loaded (by a previous lazy-loading in a call to Read, or by an explicit loading)
            if (_updateTasks == null)
            {
                _updateConditions = new Dictionary <string, Type>();
                _updateTasks      = new Dictionary <string, Type>();
                Utils.Reflection.FindTasksAndConditionsInAssembly(this.GetType().Assembly, _updateTasks, _updateConditions);
            }

            List <IUpdateTask> ret = new List <IUpdateTask>();

            XmlDocument doc = new XmlDocument();

            doc.LoadXml(feed);

            // Support for different feed versions
            XmlNode root = doc.SelectSingleNode(@"/Feed[version=""1.0""] | /Feed");

            if (root == null)
            {
                root = doc;
            }

            if (root.Attributes["BaseUrl"] != null && !string.IsNullOrEmpty(root.Attributes["BaseUrl"].Value))
            {
                UpdateManager.Instance.BaseUrl = root.Attributes["BaseUrl"].Value;
            }

            XmlNodeList nl = root.SelectNodes("./Tasks/*");

            foreach (XmlNode node in nl)
            {
                // Find the requested task type and create a new instance of it
                if (!_updateTasks.ContainsKey(node.Name))
                {
                    continue;
                }

                IUpdateTask task = (IUpdateTask)Activator.CreateInstance(_updateTasks[node.Name]);

                // Store all other task attributes, to be used by the task object later
                foreach (XmlAttribute att in node.Attributes)
                {
                    if ("type".Equals(att.Name))
                    {
                        continue;
                    }

                    task.Attributes.Add(att.Name, att.Value);
                }

                if (node.HasChildNodes)
                {
                    if (node["Description"] != null)
                    {
                        task.Description = node["Description"].InnerText;
                    }

                    // Read update conditions
                    if (node["Conditions"] != null)
                    {
                        IUpdateCondition conditionObject = ReadCondition(node["Conditions"]);
                        if (conditionObject != null)
                        {
                            if (conditionObject is BooleanCondition)
                            {
                                task.UpdateConditions = conditionObject as BooleanCondition;
                            }
                            else
                            {
                                task.UpdateConditions.AddCondition(conditionObject);
                            }
                        }
                    }
                }

                ret.Add(task);
            }
            return(ret);
        }
예제 #28
0
        public IList <IUpdateTask> Read(string feed)
        {
            // Lazy-load the Condition and Task objects contained in this assembly, unless some have already
            // been loaded (by a previous lazy-loading in a call to Read, or by an explicit loading)
            if (_updateTasks == null)
            {
                _updateConditions = new Dictionary <string, Type>();
                _updateTasks      = new Dictionary <string, Type>();
                Utils.Reflection.FindTasksAndConditionsInAssembly(this.GetType().Assembly, _updateTasks, _updateConditions);
            }

            List <IUpdateTask> ret = new List <IUpdateTask>();

            XmlDocument doc = new XmlDocument();

            doc.LoadXml(feed);

            // Support for different feed versions
            XmlNode root = doc.SelectSingleNode(@"/Feed[version=""1.0""] | /Feed") ?? doc;

            if (root.Attributes["BaseUrl"] != null && !string.IsNullOrEmpty(root.Attributes["BaseUrl"].Value))
            {
                UpdateManager.Instance.BaseUrl = root.Attributes["BaseUrl"].Value;
            }

            // Temporary collection of attributes, used to aggregate them all with their values
            // to reduce Reflection calls
            Dictionary <string, string> attributes = new Dictionary <string, string>();

            XmlNodeList nl = root.SelectNodes("./Tasks/*");

            if (nl == null)
            {
                return(new List <IUpdateTask>());                       // TODO: wrong format, probably should throw exception
            }
            foreach (XmlNode node in nl)
            {
                // Find the requested task type and create a new instance of it
                if (!_updateTasks.ContainsKey(node.Name))
                {
                    continue;
                }

                IUpdateTask task = (IUpdateTask)Activator.CreateInstance(_updateTasks[node.Name]);

                // Store all other task attributes, to be used by the task object later
                if (node.Attributes != null)
                {
                    foreach (XmlAttribute att in node.Attributes)
                    {
                        if ("type".Equals(att.Name))
                        {
                            continue;
                        }

                        attributes.Add(att.Name, att.Value);
                    }
                    if (attributes.Count > 0)
                    {
                        Utils.Reflection.SetNauAttributes(task, attributes);
                        attributes.Clear();
                    }
                    // TODO: Check to see if all required task fields have been set
                }

                if (node.HasChildNodes)
                {
                    if (node["Description"] != null)
                    {
                        task.Description = node["Description"].InnerText;
                    }

                    // Read update conditions
                    if (node["Conditions"] != null)
                    {
                        IUpdateCondition conditionObject = ReadCondition(node["Conditions"]);
                        if (conditionObject != null)
                        {
                            var boolCond = conditionObject as BooleanCondition;
                            if (boolCond != null)
                            {
                                task.UpdateConditions = boolCond;
                            }
                            else
                            {
                                if (task.UpdateConditions == null)
                                {
                                    task.UpdateConditions = new BooleanCondition();
                                }
                                task.UpdateConditions.AddCondition(conditionObject);
                            }
                        }
                    }
                }

                ret.Add(task);
            }
            return(ret);
        }