private static void Setup() { _workingDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); _logger = UpdateManager.Instance.Logger; _args = ArgumentsParser.Get(); _args.ParseCommandLineArgs(); Log("Starting to process cold updates..."); if (_args.Log) { // Setup a temporary location for the log file, until we can get the DTO _logFilePath = Path.Combine(_workingDir, @"NauUpdate.log"); } }
private static void Setup() { _workingDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); _logger = UpdateManager.Instance.Logger; _args = ArgumentsParser.Get(); _args.ParseCommandLineArgs(); if (_args.ShowConsole) { _console = new ConsoleForm(); _console.Show(); } Log("Starting to process cold updates..."); if (_args.Log) { _logFilePath = Path.Combine(_workingDir, @"NauUpdate.log"); } }
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, }; } try { NauIpc.LaunchProcessAndSendDto(dto, info, syncProcessName); } catch (Exception ex) { throw new UpdateProcessFailedException("Unable to relaunch application and/or send DTO", ex); } } 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(); } }
public static ArgumentsParser Get() { return(_instance ?? (_instance = new ArgumentsParser())); }
private static void Main() { 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..."); Log("Arguments parsed: {0}{1}.", Environment.NewLine, _args.DumpArgs()); var workingDir = Directory.GetCurrentDirectory(); 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); //TODO: I suppose this was done to load custom tasks, however there were some problems when loading an assembly which later was updated (msg: can't update because file is in use). // // Load extra assemblies to the app domain, if present // Log("Getting files in : '{0}'", workingDir); // 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(100); // hell, 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 { Console.WriteLine("Update Failed"); //MessageBox.Show(); 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); var info = new ProcessStartInfo { UseShellExecute = false, 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("Exiting."); //Must not read console! //see: http://msdn.microsoft.com/en-us/library/system.console.aspx //Especially: //Console class members that work normally when the underlying stream is directed to a console might //throw an exception if the stream is redirected, for example, to a file. Program your application to //catch System.IO.IOException exceptions if you redirect a standard stream. You can also use //the IsOutputRedirected, IsInputRedirected, and IsErrorRedirected properties to determine whether //a standard stream is redirected before performing an operation that throws an System.IO.IOException exception. } if (!string.IsNullOrEmpty(tempFolder)) { SelfCleanUp(tempFolder); } //return; //Application.Exit(); } }
private static void Main() { //Debugger.Launch(); string tempFolder = ""; try { _args = ArgumentsParser.Get(); string logFile = System.Reflection.Assembly.GetEntryAssembly().Location; logFile = Path.Combine(Path.GetDirectoryName(logFile), "logs"); logFile = Path.Combine(logFile, "NauUpdate.log"); _logger = new Logger(logFile); _args.ParseCommandLineArgs(); if (_args.ShowConsole) { _console = new ConsoleForm(); _console.Show(); } Log("=========================================="); Log("Starting..."); if (_args.Log) _console.WriteLine("Logging to {0}", logFile); // 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.", "args"); //Log("The command line needs to specify the mutex of the program to update."); Log("Object to update: '{0}'", syncProcessName); // Connect to the named pipe and retrieve the updates list var PIPE_NAME = string.Format("\\\\.\\pipe\\{0}", syncProcessName); var o = GetUpdates(PIPE_NAME); Log("Connecting to updater pipe: " + PIPE_NAME); Log(o != null ? "Connected to updater pipe." : "Failed to read updates from the updater pipe."); Log("Waiting for application to terminate."); // Make sure we start updating only once the application has completely terminated bool createdNew; using (var mutex = new Mutex(false, syncProcessName, out createdNew)) { try { if (!createdNew) mutex.WaitOne(); } catch (AbandonedMutexException) { // An abandoned mutex is exactly what we are expecting... Log("The application has terminated (as expected)."); } } bool relaunchApp = true, updateSuccessful = true; string appPath, appDir, backupFolder; { Dictionary<string, object> dict = null; if (o is Dictionary<string, object>) dict = o as Dictionary<string, object>; if (dict == null || dict.Count == 0) { throw new Exception("Could not find the updates list (or it was empty)."); //Application.Exit(); //return; } // Get some required environment variables appPath = dict["ENV:AppPath"].ToString(); appDir = dict["ENV:WorkingDirectory"] as string ?? Path.GetDirectoryName(appPath); tempFolder = dict["ENV:TempFolder"].ToString(); backupFolder = dict["ENV:BackupFolder"].ToString(); relaunchApp = dict["ENV:RelaunchApplication"] as bool? ?? true; // Perform the actual off-line update process Log("Starting the updates..."); var en = dict.GetEnumerator(); while (en.MoveNext()) { if (en.Current.Key.StartsWith("ENV:")) continue; else { Log("* Updating {0} ({1})", en.Current.Key, en.Current.Value); IUpdateAction a = null; if (en.Current.Value is string) { Log("\tCopying {0} {1}", en.Current.Value, Path.Combine(appDir, en.Current.Key)); a = new FileCopyAction(en.Current.Value.ToString(), Path.Combine(appDir, en.Current.Key)); } else if (en.Current.Value is byte[]) { Log("\tDumping {0}", en.Current.Value); a = new FileDumpAction(Path.Combine(appDir, en.Current.Key), (byte[])en.Current.Value); } if (a == null) Log("\tUpdate action: null"); else { Log("\tUpdate action: {0}", a.ToString()); try { if (!a.Do()) { Log("\tUpdate action failed: {0}", en.Current.Value); updateSuccessful = false; break; } else Log("\tUpdate action succeeded: {0}", en.Current.Value); } catch (Exception e) { MessageBox.Show("Update failed: " + e.Message); Log("\tUpdate failed: {0}", e.Message); updateSuccessful = false; break; } } } } } if (updateSuccessful) { if (Directory.Exists(backupFolder)) Directory.Delete(backupFolder, true); } else { MessageBox.Show("Update Failed."); Log("Update failed."); } // Start the application only if requested to do so if (relaunchApp) { try { Log("Relaunching the application..."); Process.Start(new ProcessStartInfo { UseShellExecute = true, WorkingDirectory = appDir, FileName = appPath, }); } catch (Win32Exception e) { MessageBox.Show(e.ToString()); Log("Update failed: " + e); } } //MessageBox.Show(string.Format("Re-launched process {0} with working dir {1}", appPath, appDir)); Log("All done."); //Application.Exit(); } catch (Exception ex) { //supressing catch because if at any point we get an error the update has failed Log("*********************************"); Log(" An error has occurred:"); Log(" " + ex.Message); Log("*********************************"); if (_args.ShowConsole) { _console.WriteLine(); _console.WriteLine("The updater will close when you close this window."); } } finally { if (_args.ShowConsole) { _console.WriteLine(); _console.WriteLine("Press any key or close this window to exit."); _console.ReadKey(); } CleanUp(tempFolder); Application.Exit(); } }
public static ArgumentsParser Get() { if (_instance == null) _instance = new ArgumentsParser(); return _instance; }
public static ArgumentsParser Get() { return _instance ?? (_instance = new ArgumentsParser()); }
private static void Main() { //Debugger.Launch(); string tempFolder = ""; try { _args = ArgumentsParser.Get(); string logFile = System.Reflection.Assembly.GetEntryAssembly().Location; logFile = Path.Combine(Path.GetDirectoryName(logFile), "logs"); logFile = Path.Combine(logFile, "NauUpdate.log"); _logger = new Logger(logFile); _args.ParseCommandLineArgs(); if (_args.ShowConsole) { _console = new ConsoleForm(); _console.Show(); } Log("Starting..."); if (_args.Log) _console.WriteLine("Logging to {0}", logFile); // 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.", "args"); Log("Update process name: '{0}'", syncProcessName); // 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 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... Log("The application has terminated (as expected)."); } } bool updateSuccessful = true; if (dto == null || dto.Configs == null) { throw new Exception("Invalid DTO received"); } Log("Got {0} task objects", dto.Tasks.Count); // 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 (dto.Tasks == null || dto.Tasks.Count == 0) { throw new Exception("Could not find the updates list (or it was empty)."); } // Perform the actual off-line update process Log("Starting the updates..."); foreach (var t in dto.Tasks) { Log("Task \"{0}\": {1}", t.Description, t.ExecutionStatus); if (t.ExecutionStatus != TaskExecutionStatus.RequiresAppRestart && t.ExecutionStatus != TaskExecutionStatus.RequiresPrivilegedAppRestart) continue; Log("\tExecuting..."); try { t.ExecutionStatus = t.Execute(true); } catch (Exception ex) { // TODO: Log message Log("\tFailed: {0}", ex.Message); updateSuccessful = false; t.ExecutionStatus = TaskExecutionStatus.Failed; MessageBox.Show("Update failed: " + ex.Message); } if (t.ExecutionStatus != TaskExecutionStatus.Successful) { Log("\tTask execution failed failed"); updateSuccessful = false; break; } } if (updateSuccessful) { Log("Finished"); Log("Removing backup folder"); if (Directory.Exists(backupFolder)) FileSystem.DeleteDirectory(backupFolder); } else { MessageBox.Show("Update Failed."); Log("Update failed."); } // Start the application only if requested to do so if (relaunchApp) { try { Log("Re-launching process {0} with working dir {1}", appPath, appDir); var info = new ProcessStartInfo { UseShellExecute = true, WorkingDirectory = appDir, FileName = appPath, }; var p = NauIpc.LaunchProcessAndSendDto(dto, info, syncProcessName); if (p == null) { Log("Unable to relaunch application"); } } catch (Win32Exception e) { MessageBox.Show(e.ToString()); Log("Update failed: " + e); } } Log("All done."); //Application.Exit(); } catch (Exception ex) { //supressing catch because if at any point we get an error the update has failed Log("*********************************"); Log(" An error has occurred:"); Log(" " + ex.Message); Log("*********************************"); if (_args.ShowConsole) { _console.WriteLine(); _console.WriteLine("The updater will close when you close this window."); } } finally { if (_args.ShowConsole) { _console.WriteLine(); _console.WriteLine("Press any key or close this window to exit."); _console.ReadKey(); } if (!string.IsNullOrEmpty(tempFolder)) SelfCleanUp(tempFolder); Application.Exit(); } }
private static void Setup() { _workingDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); _logger = UpdateManager.Instance.Logger; _args = ArgumentsParser.Get(); _args.ParseCommandLineArgs(); if (_args.ShowConsole) { _console = new ConsoleForm(); _console.Show(); } Log("Starting to process cold updates..."); if (_args.Log) { // Setup a temporary location for the log file, until we can get the DTO _logFilePath = Path.Combine(_workingDir, @"NauUpdate.log"); } }
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(System.Reflection.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.", "args"); } 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(System.Reflection.Assembly.GetEntryAssembly().Location, StringComparison.InvariantCultureIgnoreCase) || assemblyPath.EndsWith("NAppUpdate.Framework.dll")) { Log("\tSkipping (part of current execution)"); continue; } try { var assembly = System.Reflection.Assembly.LoadFile(assemblyPath); } catch (System.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(100); // hell, 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... 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); // 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) { 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); var 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"); } } 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(); } }
private static void Main() { string tempFolder = string.Empty; string logFile = string.Empty; _args = ArgumentsParser.Get(); _args.ParseCommandLineArgs(); var workingDir = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); 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"); // Load extra assemblies to the app domain, if present var availableAssemblies = FileSystem.GetFiles(workingDir, "*.exe|*.dll", SearchOption.TopDirectoryOnly); foreach (var assemblyPath in availableAssemblies) { if (assemblyPath.Equals(System.Reflection.Assembly.GetEntryAssembly().Location, StringComparison.InvariantCultureIgnoreCase) || assemblyPath.EndsWith("AppUpdate.dll")) { continue; } try { var assembly = System.Reflection.Assembly.LoadFile(assemblyPath); } catch (System.BadImageFormatException ex) { } } // 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); // hell, 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 { } } bool updateSuccessful = true; if (dto == null || dto.Configs == null) throw new Exception("Invalid DTO received"); if (dto.LogItems != null) // shouldn't really happen { } // 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 (dto.Tasks == null || dto.Tasks.Count == 0) throw new Exception("Could not find the updates list (or it was empty)."); //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) { if (t.ExecutionStatus != TaskExecutionStatus.RequiresAppRestart && t.ExecutionStatus != TaskExecutionStatus.RequiresPrivilegedAppRestart) { continue; } // TODO: Better handling on failure: logging, rollbacks try { t.ExecutionStatus = t.Execute(true); } catch (Exception ex) { updateSuccessful = false; t.ExecutionStatus = TaskExecutionStatus.Failed; } if (t.ExecutionStatus == TaskExecutionStatus.Successful) continue; updateSuccessful = false; break; } if (updateSuccessful) { if (Directory.Exists(backupFolder)) FileSystem.DeleteDirectory(backupFolder); } else { if (Directory.Exists(backupFolder)) { foreach (string backFiles in Directory.GetFiles(backupFolder, "*.*", SearchOption.AllDirectories)) { File.Copy(backFiles, backFiles.Replace(backupFolder, appDir)); } FileSystem.DeleteDirectory(backupFolder); } MessageBox.Show("Unsuccessful update. Attempted to revert."); } // Start the application only if requested to do so if (relaunchApp) { var 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"); } } catch (Exception ex) { // supressing catch because if at any point we get an error the update has failed } finally { if (!string.IsNullOrEmpty(tempFolder)) SelfCleanUp(tempFolder); Application.Exit(); } }