private static void Teardown() { if (_args.Log) { // at this stage we can't make any assumptions on correctness of the path FileSystem.CreateDirectoryStructure(_logFilePath, true); _logger.Dump(_logFilePath); } if (_args.ShowConsole) { if (_args.Log) { _console.WriteLine(); _console.WriteLine("Log file was saved to {0}", _logFilePath); _console.WriteLine(); } _console.WriteLine(); _console.WriteLine("Press any key or close this window to exit."); _console.ReadKey(); } if (_dto != null && _dto.Configs != null & !string.IsNullOrEmpty(_dto.Configs.TempFolder)) { SelfCleanUp(_dto.Configs.TempFolder); } Application.Exit(); }
private static void Main() { //Debugger.Launch(); string tempFolder = string.Empty; string logFile = string.Empty; _args = ArgumentsParser.Get(); _logger = UpdateManager.Instance.Logger; _args.ParseCommandLineArgs(); if (_args.ShowConsole) { _console = new ConsoleForm(); _console.Show(); } Log("Starting to process cold updates..."); var workingDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); if (_args.Log) { // Setup a temporary location for the log file, until we can get the DTO logFile = Path.Combine(workingDir, @"NauUpdate.log"); } try { // Get the update process name, to be used to create a named pipe and to wait on the application // to quit string syncProcessName = _args.ProcessName; if (string.IsNullOrEmpty(syncProcessName)) //Application.Exit(); { throw new ArgumentException("The command line needs to specify the mutex of the program to update.", "ar" + "gs"); } Log("Update process name: '{0}'", syncProcessName); // Load extra assemblies to the app domain, if present var availableAssemblies = FileSystem.GetFiles(workingDir, "*.exe|*.dll", SearchOption.TopDirectoryOnly); foreach (var assemblyPath in availableAssemblies) { Log("Loading {0}", assemblyPath); if (assemblyPath.Equals(Assembly.GetEntryAssembly().Location, StringComparison.InvariantCultureIgnoreCase) || assemblyPath.EndsWith("NAppUpdate.Framework.dll")) { Log("\tSkipping (part of current execution)"); continue; } try { // ReSharper disable UnusedVariable var assembly = Assembly.LoadFile(assemblyPath); // ReSharper restore UnusedVariable } catch (BadImageFormatException ex) { Log("\tSkipping due to an error: {0}", ex.Message); } } // Connect to the named pipe and retrieve the updates list var dto = NauIpc.ReadDto(syncProcessName) as NauIpc.NauDto; // Make sure we start updating only once the application has completely terminated Thread.Sleep(1000); // Let's even wait a bit bool createdNew; using (var mutex = new Mutex(false, syncProcessName + "Mutex", out createdNew)) { try { if (!createdNew) { mutex.WaitOne(); } } catch (AbandonedMutexException) { // An abandoned mutex is exactly what we are expecting... } finally { Log("The application has terminated (as expected)"); } } bool updateSuccessful = true; if (dto == null || dto.Configs == null) { throw new Exception("Invalid DTO received"); } if (dto.LogItems != null) // shouldn't really happen { _logger.LogItems.InsertRange(0, dto.LogItems); } dto.LogItems = _logger.LogItems; // Get some required environment variables string appPath = dto.AppPath; string appDir = dto.WorkingDirectory ?? Path.GetDirectoryName(appPath) ?? string.Empty; tempFolder = dto.Configs.TempFolder; string backupFolder = dto.Configs.BackupFolder; bool relaunchApp = dto.RelaunchApplication; if (!string.IsNullOrEmpty(dto.AppPath)) { logFile = Path.Combine(Path.GetDirectoryName(dto.AppPath), @"NauUpdate.log"); // now we can log to a more accessible location } if (dto.Tasks == null || dto.Tasks.Count == 0) { throw new Exception("Could not find the updates list (or it was empty)."); } Log("Got {0} task objects", dto.Tasks.Count); //This can be handy if you're trying to debug the updater.exe! //#if (DEBUG) { if (_args.ShowConsole) { _console.WriteLine(); _console.WriteLine("Pausing to attach debugger. Press any key to continue."); _console.ReadKey(); } } //#endif // Perform the actual off-line update process foreach (var t in dto.Tasks) { Log("Task \"{0}\": {1}", t.Description, t.ExecutionStatus); if (t.ExecutionStatus != TaskExecutionStatus.RequiresAppRestart && t.ExecutionStatus != TaskExecutionStatus.RequiresPrivilegedAppRestart) { Log("\tSkipping"); continue; } Log("\tExecuting..."); // TODO: Better handling on failure: logging, rollbacks try { t.ExecutionStatus = t.Execute(true); } catch (Exception ex) { Log(ex); updateSuccessful = false; t.ExecutionStatus = TaskExecutionStatus.Failed; } if (t.ExecutionStatus == TaskExecutionStatus.Successful) { continue; } Log("\tTask execution failed"); updateSuccessful = false; break; } if (updateSuccessful) { Log("Finished successfully"); Log("Removing backup folder"); if (Directory.Exists(backupFolder)) { FileSystem.DeleteDirectory(backupFolder); } } else { MessageBox.Show("Update Failed"); Log(Logger.SeverityLevel.Error, "Update failed"); } // Start the application only if requested to do so if (relaunchApp) { Log("Re-launching process {0} with working dir {1}", appPath, appDir); ProcessStartInfo info; if (_args.ShowConsole) { info = new ProcessStartInfo { UseShellExecute = false, WorkingDirectory = appDir, FileName = appPath, }; } else { info = new ProcessStartInfo { UseShellExecute = true, WorkingDirectory = appDir, FileName = appPath, }; } var p = NauIpc.LaunchProcessAndSendDto(dto, info, syncProcessName); if (p == null) { throw new UpdateProcessFailedException("Unable to relaunch application and/or send DTO"); } } Log("All done"); //Application.Exit(); } catch (Exception ex) { // supressing catch because if at any point we get an error the update has failed Log(ex); } finally { if (_args.Log) { // at this stage we can't make any assumptions on correctness of the path FileSystem.CreateDirectoryStructure(logFile, true); _logger.Dump(logFile); } if (_args.ShowConsole) { if (_args.Log) { _console.WriteLine(); _console.WriteLine("Log file was saved to {0}", logFile); _console.WriteLine(); } _console.WriteLine(); _console.WriteLine("Press any key or close this window to exit."); _console.ReadKey(); } if (!string.IsNullOrEmpty(tempFolder)) { SelfCleanUp(tempFolder); } Application.Exit(); } }